CTS Unit tests for MediaExtractor Native

Bug: 144991581
Test: atest --test android.mediav2.cts.ExtractorUnitTest

Change-Id: Ic77f2c8e2474f26191e7ecdbf2ef7afcb2718f7b
diff --git a/tests/media/jni/Android.bp b/tests/media/jni/Android.bp
index 10f0f59..b8e4314 100644
--- a/tests/media/jni/Android.bp
+++ b/tests/media/jni/Android.bp
@@ -23,6 +23,9 @@
         "libmediandk",
         "liblog",
     ],
+    include_dirs: [
+        "frameworks/av/media/ndk/include/media",
+    ],
     stl: "libc++_static",
     cflags: [
         "-Werror",
@@ -36,11 +39,15 @@
     srcs: [
         "NativeMediaConstants.cpp",
         "NativeExtractorTest.cpp",
+        "NativeExtractorUnitTest.cpp",
     ],
     shared_libs: [
         "libmediandk",
         "liblog",
     ],
+    include_dirs: [
+        "frameworks/av/media/ndk/include/media",
+    ],
     stl: "libc++_static",
     cflags: [
         "-Werror",
diff --git a/tests/media/jni/NativeExtractorTest.cpp b/tests/media/jni/NativeExtractorTest.cpp
index 42876f0..60df304 100644
--- a/tests/media/jni/NativeExtractorTest.cpp
+++ b/tests/media/jni/NativeExtractorTest.cpp
@@ -18,14 +18,13 @@
 #define LOG_TAG "NativeExtractorTest"
 #include <log/log.h>
 
+#include <NdkMediaExtractor.h>
 #include <jni.h>
 #include <sys/stat.h>
 
 #include <cstdlib>
 #include <random>
 
-#include "media/NdkMediaExtractor.h"
-
 static bool isExtractorOKonEOS(AMediaExtractor* extractor) {
     return AMediaExtractor_getSampleTrackIndex(extractor) < 0 &&
            AMediaExtractor_getSampleSize(extractor) < 0 &&
@@ -726,10 +725,13 @@
     return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
 }
 
+extern int registerAndroidMediaV2CtsExtractorUnitTestApi(JNIEnv* env);
+
 extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
     JNIEnv* env;
     if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) return JNI_ERR;
     if (registerAndroidMediaV2CtsExtractorTestSetDS(env) != JNI_OK) return JNI_ERR;
     if (registerAndroidMediaV2CtsExtractorTestFunc(env) != JNI_OK) return JNI_ERR;
+    if (registerAndroidMediaV2CtsExtractorUnitTestApi(env) != JNI_OK) return JNI_ERR;
     return JNI_VERSION_1_6;
 }
\ No newline at end of file
diff --git a/tests/media/jni/NativeExtractorUnitTest.cpp b/tests/media/jni/NativeExtractorUnitTest.cpp
new file mode 100644
index 0000000..2abc515
--- /dev/null
+++ b/tests/media/jni/NativeExtractorUnitTest.cpp
@@ -0,0 +1,489 @@
+/*
+ * Copyright (C) 2019 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 "NativeExtractorUnitTest"
+#include <log/log.h>
+
+#include <NdkMediaExtractor.h>
+#include <jni.h>
+#include <sys/stat.h>
+
+#include <cstdlib>
+#include <cstring>
+
+static media_status_t setExtractorDataSource(AMediaExtractor* extractor, FILE* fp) {
+    media_status_t status = AMEDIA_ERROR_BASE;
+    struct stat buf {};
+    if (fp && !fstat(fileno(fp), &buf))
+        status = AMediaExtractor_setDataSourceFd(extractor, fileno(fp), 0, buf.st_size);
+    if (status != AMEDIA_OK) ALOGE("error: AMediaExtractor_setDataSourceFd failed %d", status);
+    return status;
+}
+
+static jboolean nativeTestGetTrackCountBeforeSetDataSource(JNIEnv*, jobject) {
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    bool isPass = (0 == AMediaExtractor_getTrackCount(extractor));
+    if (!isPass) ALOGE("error: received valid trackCount before setDataSource");
+    AMediaExtractor_delete(extractor);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestSelectTrackBeforeSetDataSource(JNIEnv*, jobject) {
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    bool isPass = (AMEDIA_OK != AMediaExtractor_selectTrack(extractor, 0));
+    if (!isPass) ALOGE("error: selectTrack succeeds before setDataSource");
+    AMediaExtractor_delete(extractor);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestSelectTrackForInvalidIndex(JNIEnv* env, jobject, jstring jsrcPath) {
+    bool isPass = false;
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    FILE* srcFp = fopen(csrcPath, "rbe");
+    if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
+        if (AMEDIA_OK !=
+            AMediaExtractor_selectTrack(extractor, AMediaExtractor_getTrackCount(extractor))) {
+            isPass = true;
+        } else {
+            ALOGE("error: selectTrack succeeds for out of bounds track index: %zu",
+                  AMediaExtractor_getTrackCount(extractor));
+        }
+    }
+    AMediaExtractor_delete(extractor);
+    if (srcFp) fclose(srcFp);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestIdempotentSelectTrack(JNIEnv* env, jobject, jstring jsrcPath) {
+    bool isPass = false;
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    FILE* srcFp = fopen(csrcPath, "rbe");
+    if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
+        isPass = AMediaExtractor_selectTrack(extractor, 0) == AMEDIA_OK;
+        isPass &= AMediaExtractor_selectTrack(extractor, 0) == AMEDIA_OK;
+        if (!isPass) ALOGE("error: multiple selection of same track has failed");
+    }
+    AMediaExtractor_delete(extractor);
+    if (srcFp) fclose(srcFp);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestUnselectTrackBeforeSetDataSource(JNIEnv*, jobject) {
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    bool isPass = (AMEDIA_OK != AMediaExtractor_unselectTrack(extractor, 0));
+    if (!isPass) ALOGE("error: unselectTrack succeeds before setDataSource");
+    AMediaExtractor_delete(extractor);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestUnselectTrackForInvalidIndex(JNIEnv* env, jobject, jstring jsrcPath) {
+    bool isPass = false;
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    FILE* srcFp = fopen(csrcPath, "rbe");
+    if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
+        if (AMEDIA_OK !=
+            AMediaExtractor_unselectTrack(extractor, AMediaExtractor_getTrackCount(extractor))) {
+            isPass = true;
+        } else {
+            ALOGE("error: unselectTrack succeeds for out of bounds track index: %zu",
+                  AMediaExtractor_getTrackCount(extractor));
+        }
+    }
+    AMediaExtractor_delete(extractor);
+    if (srcFp) fclose(srcFp);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestUnselectTrackForUnSelectedTrackIndex(JNIEnv* env, jobject,
+                                                               jstring jsrcPath) {
+    bool isPass = false;
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    FILE* srcFp = fopen(csrcPath, "rbe");
+    if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
+        isPass = (AMediaExtractor_unselectTrack(extractor, 0) == AMEDIA_OK);
+        if (!isPass) ALOGE("error: un-selection of non-selected track has failed");
+    }
+    AMediaExtractor_delete(extractor);
+    if (srcFp) fclose(srcFp);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestIdempotentUnselectTrack(JNIEnv* env, jobject, jstring jsrcPath) {
+    bool isPass = false;
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    FILE* srcFp = fopen(csrcPath, "rbe");
+    if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
+        isPass = AMediaExtractor_selectTrack(extractor, 0) == AMEDIA_OK;
+        if (isPass) {
+            isPass = AMediaExtractor_unselectTrack(extractor, 0) == AMEDIA_OK;
+            isPass &= AMediaExtractor_unselectTrack(extractor, 0) == AMEDIA_OK;
+            if (!isPass) ALOGE("error: multiple unselection of selected track has failed");
+        } else {
+            ALOGE("error: selection of track 0 has failed for file %s", csrcPath);
+        }
+    }
+    AMediaExtractor_delete(extractor);
+    if (srcFp) fclose(srcFp);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestSeekToBeforeSetDataSource(JNIEnv*, jobject) {
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    bool isPass = AMediaExtractor_seekTo(extractor, 0, AMEDIAEXTRACTOR_SEEK_NEXT_SYNC) != AMEDIA_OK;
+    if (!isPass) ALOGE("error: seekTo() succeeds before setting data source");
+    AMediaExtractor_delete(extractor);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestSeekToBeforeSelectTrack(JNIEnv* env, jobject, jstring jsrcPath) {
+    bool isPass = false;
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    FILE* srcFp = fopen(csrcPath, "rbe");
+    if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
+        isPass = AMediaExtractor_seekTo(extractor, 0, AMEDIAEXTRACTOR_SEEK_NEXT_SYNC) != AMEDIA_OK;
+        if (!isPass) ALOGE("error: seekTo() succeeds before selecting track");
+    }
+    AMediaExtractor_delete(extractor);
+    if (srcFp) fclose(srcFp);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestGetCachedDurationBeforeSetDataSource(JNIEnv*, jobject) {
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    bool isPass = AMediaExtractor_getCachedDuration(extractor) == -1;
+    if (!isPass) ALOGE("error: getCachedDuration returns unexpected value before setDataSource");
+    AMediaExtractor_delete(extractor);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestIfGetFileFormatSucceedsBeforeSetDataSource(JNIEnv*, jobject) {
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    AMediaFormat* empty = AMediaFormat_new();
+    AMediaFormat* format = AMediaExtractor_getFileFormat(extractor);
+    bool isPass = true;
+    if (format == nullptr ||
+        strcmp(AMediaFormat_toString(empty), AMediaFormat_toString(format)) != 0) {
+        isPass = false;
+        ALOGE("error: getFileFormat before set data source yields unexpected result");
+    }
+    if (format) AMediaFormat_delete(format);
+    AMediaFormat_delete(empty);
+    AMediaExtractor_delete(extractor);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestAdvanceBeforeSetDataSource(JNIEnv*, jobject) {
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    bool isPass = !AMediaExtractor_advance(extractor);
+    if (!isPass) ALOGE("error: advance succeeds before setDataSource");
+    AMediaExtractor_delete(extractor);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestAdvanceBeforeSelectTrack(JNIEnv* env, jobject, jstring jsrcPath) {
+    bool isPass = false;
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    FILE* srcFp = fopen(csrcPath, "rbe");
+    if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
+        isPass = !AMediaExtractor_advance(extractor);
+        if (!isPass) ALOGE("error: advance succeeds without any active tracks");
+    }
+    AMediaExtractor_delete(extractor);
+    if (srcFp) fclose(srcFp);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestGetSampleFlagsBeforeSetDataSource(JNIEnv*, jobject) {
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    bool isPass = AMediaExtractor_getSampleFlags(extractor) == -1;
+    if (!isPass) ALOGE("error: received valid sample flag before setDataSource");
+    AMediaExtractor_delete(extractor);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestGetSampleFlagsBeforeSelectTrack(JNIEnv* env, jobject, jstring jsrcPath) {
+    bool isPass = false;
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    FILE* srcFp = fopen(csrcPath, "rbe");
+    if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
+        isPass = AMediaExtractor_getSampleFlags(extractor) == -1;
+        if (!isPass) ALOGE("error: received valid sample flag without any active tracks");
+    }
+    AMediaExtractor_delete(extractor);
+    if (srcFp) fclose(srcFp);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestGetSampleTimeBeforeSetDataSource(JNIEnv*, jobject) {
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    bool isPass = AMediaExtractor_getSampleTime(extractor) == -1;
+    if (!isPass) ALOGE("error: received valid pts before setDataSource");
+    AMediaExtractor_delete(extractor);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestGetSampleTimeBeforeSelectTrack(JNIEnv* env, jobject, jstring jsrcPath) {
+    bool isPass = false;
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    FILE* srcFp = fopen(csrcPath, "rbe");
+    if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
+        isPass = AMediaExtractor_getSampleTime(extractor) == -1;
+        if (!isPass) ALOGE("error: received valid pts without any active tracks");
+    }
+    AMediaExtractor_delete(extractor);
+    if (srcFp) fclose(srcFp);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestGetSampleSizeBeforeSetDataSource(JNIEnv*, jobject) {
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    bool isPass = AMediaExtractor_getSampleSize(extractor) == -1;
+    if (!isPass) ALOGE("error: received valid sample size before setDataSource");
+    AMediaExtractor_delete(extractor);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestGetSampleSizeBeforeSelectTrack(JNIEnv* env, jobject, jstring jsrcPath) {
+    bool isPass = false;
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    FILE* srcFp = fopen(csrcPath, "rbe");
+    if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
+        isPass = AMediaExtractor_getSampleSize(extractor) == -1;
+        if (!isPass) ALOGE("error: received valid sample size without any active tracks");
+    }
+    AMediaExtractor_delete(extractor);
+    if (srcFp) fclose(srcFp);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestIfGetSampleFormatBeforeSetDataSource(JNIEnv*, jobject) {
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    AMediaFormat* format = AMediaFormat_new();
+    bool isPass = AMediaExtractor_getSampleFormat(extractor, format) != AMEDIA_OK;
+    if (!isPass) ALOGE("error: getSampleFormat succeeds before setDataSource");
+    AMediaFormat_delete(format);
+    AMediaExtractor_delete(extractor);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestIfGetSampleFormatBeforeSelectTrack(JNIEnv* env, jobject,
+                                                             jstring jsrcPath) {
+    bool isPass = false;
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    AMediaFormat* format = AMediaFormat_new();
+    FILE* srcFp = fopen(csrcPath, "rbe");
+    if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
+        isPass = AMediaExtractor_getSampleFormat(extractor, format) != AMEDIA_OK;
+        if (!isPass) ALOGE("error: getSampleFormat succeeds without any active tracks");
+    }
+    AMediaFormat_delete(format);
+    AMediaExtractor_delete(extractor);
+    if (srcFp) fclose(srcFp);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestGetSampleTrackIndexBeforeSetDataSource(JNIEnv*, jobject) {
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    bool isPass = AMediaExtractor_getSampleTrackIndex(extractor) == -1;
+    if (!isPass) ALOGE("error: received valid track index before setDataSource");
+    AMediaExtractor_delete(extractor);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestGetSampleTrackIndexBeforeSelectTrack(JNIEnv* env, jobject,
+                                                               jstring jsrcPath) {
+    bool isPass = false;
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    FILE* srcFp = fopen(csrcPath, "rbe");
+    if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
+        isPass = AMediaExtractor_getSampleTrackIndex(extractor) == -1;
+        if (!isPass) ALOGE("error: received valid track index without any active tracks");
+    }
+    AMediaExtractor_delete(extractor);
+    if (srcFp) fclose(srcFp);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestGetTrackFormatBeforeSetDataSource(JNIEnv*, jobject) {
+    bool isPass = true;
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    AMediaFormat* empty = AMediaFormat_new();
+    AMediaFormat* format = AMediaExtractor_getTrackFormat(extractor, 0);
+    if (format == nullptr ||
+        strcmp(AMediaFormat_toString(empty), AMediaFormat_toString(format)) != 0) {
+        isPass = false;
+        ALOGE("error: getTrackFormat before setDataSource yields unexpected result");
+    }
+    if (format) AMediaFormat_delete(format);
+    AMediaFormat_delete(empty);
+    AMediaExtractor_delete(extractor);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestGetTrackFormatForInvalidIndex(JNIEnv* env, jobject, jstring jsrcPath) {
+    bool isPass = true;
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    FILE* srcFp = fopen(csrcPath, "rbe");
+    if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
+        AMediaFormat* format =
+                AMediaExtractor_getTrackFormat(extractor, AMediaExtractor_getTrackCount(extractor));
+        AMediaFormat* empty = AMediaFormat_new();
+        if (format == nullptr ||
+            strcmp(AMediaFormat_toString(empty), AMediaFormat_toString(format)) != 0) {
+            isPass = false;
+            ALOGE("error: getTrackFormat for out of bound track index %zu yields unexpected result",
+                  AMediaExtractor_getTrackCount(extractor));
+        }
+        if (format) AMediaFormat_delete(format);
+        AMediaFormat_delete(empty);
+    } else {
+        isPass = false;
+    }
+    AMediaExtractor_delete(extractor);
+    if (srcFp) fclose(srcFp);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestReadSampleDataBeforeSetDataSource(JNIEnv*, jobject) {
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    const int maxSampleSize = 512 * 1024;
+    auto buffer = new uint8_t[maxSampleSize];
+    bool isPass = AMediaExtractor_readSampleData(extractor, buffer, maxSampleSize) < 0;
+    if (!isPass) ALOGE("error: readSampleData return non-negative readBytes before setDataSource");
+    delete[] buffer;
+    AMediaExtractor_delete(extractor);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestReadSampleDataBeforeSelectTrack(JNIEnv* env, jobject, jstring jsrcPath) {
+    bool isPass = false;
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    const int maxSampleSize = (512 * 1024);
+    auto buffer = new uint8_t[maxSampleSize];
+    FILE* srcFp = fopen(csrcPath, "rbe");
+    if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
+        isPass = AMediaExtractor_readSampleData(extractor, buffer, maxSampleSize) < 0;
+        if (!isPass) {
+            ALOGE("error: readSampleData returns non-negative readBytes with out active tracks");
+        }
+    }
+    delete[] buffer;
+    AMediaExtractor_delete(extractor);
+    if (srcFp) fclose(srcFp);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestIfNullLocationIsRejectedBySetDataSource(JNIEnv*, jobject) {
+    AMediaExtractor* extractor = AMediaExtractor_new();
+    bool isPass = AMediaExtractor_setDataSource(extractor, nullptr) != AMEDIA_OK;
+    if (!isPass) ALOGE("error: setDataSource succeeds with null location");
+    AMediaExtractor_delete(extractor);
+    return static_cast<jboolean>(isPass);
+}
+
+int registerAndroidMediaV2CtsExtractorUnitTestApi(JNIEnv* env) {
+    const JNINativeMethod methodTable[] = {
+            {"nativeTestGetTrackCountBeforeSetDataSource", "()Z",
+             (void*)nativeTestGetTrackCountBeforeSetDataSource},
+            {"nativeTestSelectTrackBeforeSetDataSource", "()Z",
+             (void*)nativeTestSelectTrackBeforeSetDataSource},
+            {"nativeTestSelectTrackForInvalidIndex", "(Ljava/lang/String;)Z",
+             (void*)nativeTestSelectTrackForInvalidIndex},
+            {"nativeTestIdempotentSelectTrack", "(Ljava/lang/String;)Z",
+             (void*)nativeTestIdempotentSelectTrack},
+            {"nativeTestUnselectTrackBeforeSetDataSource", "()Z",
+             (void*)nativeTestUnselectTrackBeforeSetDataSource},
+            {"nativeTestUnselectTrackForInvalidIndex", "(Ljava/lang/String;)Z",
+             (void*)nativeTestUnselectTrackForInvalidIndex},
+            {"nativeTestUnselectTrackForUnSelectedTrackIndex", "(Ljava/lang/String;)Z",
+             (void*)nativeTestUnselectTrackForUnSelectedTrackIndex},
+            {"nativeTestIdempotentUnselectTrack", "(Ljava/lang/String;)Z",
+             (void*)nativeTestIdempotentUnselectTrack},
+            {"nativeTestSeekToBeforeSetDataSource", "()Z",
+             (void*)nativeTestSeekToBeforeSetDataSource},
+            {"nativeTestSeekToBeforeSelectTrack", "(Ljava/lang/String;)Z",
+             (void*)nativeTestSeekToBeforeSelectTrack},
+            {"nativeTestGetCachedDurationBeforeSetDataSource", "()Z",
+             (void*)nativeTestGetCachedDurationBeforeSetDataSource},
+            {"nativeTestIfGetFileFormatSucceedsBeforeSetDataSource", "()Z",
+             (void*)nativeTestIfGetFileFormatSucceedsBeforeSetDataSource},
+            {"nativeTestAdvanceBeforeSetDataSource", "()Z",
+             (void*)nativeTestAdvanceBeforeSetDataSource},
+            {"nativeTestAdvanceBeforeSelectTrack", "(Ljava/lang/String;)Z",
+             (void*)nativeTestAdvanceBeforeSelectTrack},
+            {"nativeTestGetSampleFlagsBeforeSetDataSource", "()Z",
+             (void*)nativeTestGetSampleFlagsBeforeSetDataSource},
+            {"nativeTestGetSampleFlagsBeforeSelectTrack", "(Ljava/lang/String;)Z",
+             (void*)nativeTestGetSampleFlagsBeforeSelectTrack},
+            {"nativeTestGetSampleTimeBeforeSetDataSource", "()Z",
+             (void*)nativeTestGetSampleTimeBeforeSetDataSource},
+            {"nativeTestGetSampleTimeBeforeSelectTrack", "(Ljava/lang/String;)Z",
+             (void*)nativeTestGetSampleTimeBeforeSelectTrack},
+            {"nativeTestGetSampleSizeBeforeSetDataSource", "()Z",
+             (void*)nativeTestGetSampleSizeBeforeSetDataSource},
+            {"nativeTestGetSampleSizeBeforeSelectTrack", "(Ljava/lang/String;)Z",
+             (void*)nativeTestGetSampleSizeBeforeSelectTrack},
+            {"nativeTestIfGetSampleFormatBeforeSetDataSource", "()Z",
+             (void*)nativeTestIfGetSampleFormatBeforeSetDataSource},
+            {"nativeTestIfGetSampleFormatBeforeSelectTrack", "(Ljava/lang/String;)Z",
+             (void*)nativeTestIfGetSampleFormatBeforeSelectTrack},
+            {"nativeTestGetSampleTrackIndexBeforeSetDataSource", "()Z",
+             (void*)nativeTestGetSampleTrackIndexBeforeSetDataSource},
+            {"nativeTestGetSampleTrackIndexBeforeSelectTrack", "(Ljava/lang/String;)Z",
+             (void*)nativeTestGetSampleTrackIndexBeforeSelectTrack},
+            {"nativeTestGetTrackFormatBeforeSetDataSource", "()Z",
+             (void*)nativeTestGetTrackFormatBeforeSetDataSource},
+            {"nativeTestGetTrackFormatForInvalidIndex", "(Ljava/lang/String;)Z",
+             (void*)nativeTestGetTrackFormatForInvalidIndex},
+            {"nativeTestReadSampleDataBeforeSetDataSource", "()Z",
+             (void*)nativeTestReadSampleDataBeforeSetDataSource},
+            {"nativeTestReadSampleDataBeforeSelectTrack", "(Ljava/lang/String;)Z",
+             (void*)nativeTestReadSampleDataBeforeSelectTrack},
+            {"nativeTestIfNullLocationIsRejectedBySetDataSource", "()Z",
+             (void*)nativeTestIfNullLocationIsRejectedBySetDataSource},
+    };
+    jclass c = env->FindClass("android/mediav2/cts/ExtractorUnitTest$TestApiNative");
+    return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
+}
diff --git a/tests/media/jni/NativeMuxerTest.cpp b/tests/media/jni/NativeMuxerTest.cpp
index 62d1535..8d73431 100644
--- a/tests/media/jni/NativeMuxerTest.cpp
+++ b/tests/media/jni/NativeMuxerTest.cpp
@@ -18,6 +18,9 @@
 #define LOG_TAG "NativeMuxerTest"
 #include <log/log.h>
 
+#include <NdkMediaExtractor.h>
+#include <NdkMediaFormat.h>
+#include <NdkMediaMuxer.h>
 #include <fcntl.h>
 #include <jni.h>
 #include <sys/stat.h>
@@ -30,9 +33,6 @@
 #include <vector>
 
 #include "NativeMediaConstants.h"
-#include "media/NdkMediaExtractor.h"
-#include "media/NdkMediaFormat.h"
-#include "media/NdkMediaMuxer.h"
 
 /**
  * MuxerNativeTestHelper breaks a media file to elements that a muxer can use to rebuild its clone.
diff --git a/tests/media/jni/NativeMuxerUnitTest.cpp b/tests/media/jni/NativeMuxerUnitTest.cpp
index e267799..a08c921 100644
--- a/tests/media/jni/NativeMuxerUnitTest.cpp
+++ b/tests/media/jni/NativeMuxerUnitTest.cpp
@@ -17,6 +17,10 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "NativeMuxerUnitTest"
 #include <log/log.h>
+
+#include <NdkMediaExtractor.h>
+#include <NdkMediaFormat.h>
+#include <NdkMediaMuxer.h>
 #include <fcntl.h>
 #include <jni.h>
 #include <sys/stat.h>
@@ -29,9 +33,6 @@
 #include <vector>
 
 #include "NativeMediaConstants.h"
-#include "media/NdkMediaExtractor.h"
-#include "media/NdkMediaFormat.h"
-#include "media/NdkMediaMuxer.h"
 
 static media_status_t insertPerFrameSubtitles(AMediaMuxer* muxer, long pts, size_t trackID) {
     const char* greeting = "hello world";
diff --git a/tests/media/src/android/mediav2/cts/ExtractorUnitTest.java b/tests/media/src/android/mediav2/cts/ExtractorUnitTest.java
index 84122cd..a28f134 100644
--- a/tests/media/src/android/mediav2/cts/ExtractorUnitTest.java
+++ b/tests/media/src/android/mediav2/cts/ExtractorUnitTest.java
@@ -790,4 +790,190 @@
             }
         }
     }
+
+    @SmallTest
+    public static class TestApiNative {
+        @Rule
+        public TestName testName = new TestName();
+
+        static {
+            System.loadLibrary("ctsmediav2extractor_jni");
+        }
+
+        @Test
+        public void testGetTrackCountBeforeSetDataSource() {
+            assertTrue(nativeTestGetTrackCountBeforeSetDataSource());
+        }
+        private native boolean nativeTestGetTrackCountBeforeSetDataSource();
+
+        @Test
+        public void testSelectTrackBeforeSetDataSource() {
+            assertTrue(nativeTestSelectTrackBeforeSetDataSource());
+        }
+        private native boolean nativeTestSelectTrackBeforeSetDataSource();
+
+        @Test
+        public void testSelectTrackForInvalidIndex() {
+            assertTrue(nativeTestSelectTrackForInvalidIndex(mInpPrefix + mInpMedia));
+        }
+        private native boolean nativeTestSelectTrackForInvalidIndex(String srcPath);
+
+        @Test
+        public void testIdempotentSelectTrack() {
+            assertTrue(nativeTestIdempotentSelectTrack(mInpPrefix + mInpMedia));
+        }
+        private native boolean nativeTestIdempotentSelectTrack(String srcPath);
+
+        @Test
+        public void testUnselectTrackBeforeSetDataSource() {
+            assertTrue(nativeTestUnselectTrackBeforeSetDataSource());
+        }
+        private native boolean nativeTestUnselectTrackBeforeSetDataSource();
+
+        @Test
+        public void testUnselectTrackForInvalidIndex() {
+            assertTrue(nativeTestUnselectTrackForInvalidIndex(mInpPrefix + mInpMedia));
+        }
+        private native boolean nativeTestUnselectTrackForInvalidIndex(String srcPath);
+
+        @Test
+        public void testUnselectTrackForUnSelectedTrackIndex() {
+            assertTrue(nativeTestUnselectTrackForUnSelectedTrackIndex(mInpPrefix + mInpMedia));
+        }
+        private native boolean nativeTestUnselectTrackForUnSelectedTrackIndex(String srcPath);
+
+        @Test
+        public void testIdempotentUnselectTrack() {
+            assertTrue(nativeTestIdempotentUnselectTrack(mInpPrefix + mInpMedia));
+        }
+        private native boolean nativeTestIdempotentUnselectTrack(String srcPath);
+
+        @Test
+        public void testSeekToBeforeSetDataSource() {
+            assertTrue(nativeTestSeekToBeforeSetDataSource());
+        }
+        private native boolean nativeTestSeekToBeforeSetDataSource();
+
+        @Test
+        public void testSeekToBeforeSelectTrack() {
+            assertTrue(nativeTestSeekToBeforeSelectTrack(mInpPrefix + mInpMedia));
+        }
+        private native boolean nativeTestSeekToBeforeSelectTrack(String srcPath);
+
+        @Test
+        @Ignore("TODO(b/148205432)")
+        public void testGetCachedDurationBeforeSetDataSource() {
+            assertTrue(nativeTestGetCachedDurationBeforeSetDataSource());
+        }
+        private native boolean nativeTestGetCachedDurationBeforeSetDataSource();
+
+        @Test
+        public void testIfGetFileFormatSucceedsBeforeSetDataSource() {
+            assertTrue(nativeTestIfGetFileFormatSucceedsBeforeSetDataSource());
+        }
+        private native boolean nativeTestIfGetFileFormatSucceedsBeforeSetDataSource();
+
+        @Test
+        public void testAdvanceBeforeSetDataSource() {
+            assertTrue(nativeTestAdvanceBeforeSetDataSource());
+        }
+        private native boolean nativeTestAdvanceBeforeSetDataSource();
+
+        @Test
+        public void testAdvanceBeforeSelectTrack() {
+            assertTrue(nativeTestAdvanceBeforeSelectTrack(mInpPrefix + mInpMedia));
+        }
+        private native boolean nativeTestAdvanceBeforeSelectTrack(String srcPath);
+
+        @Test
+        public void testGetSampleFlagsBeforeSetDataSource() {
+            assertTrue(nativeTestGetSampleFlagsBeforeSetDataSource());
+        }
+        private native boolean nativeTestGetSampleFlagsBeforeSetDataSource();
+
+        @Test
+        public void testGetSampleFlagsBeforeSelectTrack() {
+            assertTrue(nativeTestGetSampleFlagsBeforeSelectTrack(mInpPrefix + mInpMedia));
+        }
+        private native boolean nativeTestGetSampleFlagsBeforeSelectTrack(String srcPath);
+
+        @Test
+        public void testGetSampleTimeBeforeSetDataSource() {
+            assertTrue(nativeTestGetSampleTimeBeforeSetDataSource());
+        }
+        private native boolean nativeTestGetSampleTimeBeforeSetDataSource();
+
+        @Test
+        public void testGetSampleTimeBeforeSelectTrack() {
+            assertTrue(nativeTestGetSampleTimeBeforeSelectTrack(mInpPrefix + mInpMedia));
+        }
+        private native boolean nativeTestGetSampleTimeBeforeSelectTrack(String srcPath);
+
+        @Test
+        public void testGetSampleSizeBeforeSetDataSource() {
+            assertTrue(nativeTestGetSampleSizeBeforeSetDataSource());
+        }
+        private native boolean nativeTestGetSampleSizeBeforeSetDataSource();
+
+        @Test
+        public void testGetSampleSizeBeforeSelectTrack() {
+            assertTrue(nativeTestGetSampleSizeBeforeSelectTrack(mInpPrefix + mInpMedia));
+        }
+        private native boolean nativeTestGetSampleSizeBeforeSelectTrack(String srcPath);
+
+        @Test
+        public void testIfGetSampleFormatBeforeSetDataSource() {
+            assertTrue(nativeTestIfGetSampleFormatBeforeSetDataSource());
+        }
+        private native boolean nativeTestIfGetSampleFormatBeforeSetDataSource();
+
+        @Test
+        public void testIfGetSampleFormatBeforeSelectTrack() {
+            assertTrue(nativeTestIfGetSampleFormatBeforeSelectTrack(mInpPrefix + mInpMedia));
+        }
+        private native boolean nativeTestIfGetSampleFormatBeforeSelectTrack(String srcPath);
+
+        @Test
+        public void testGetSampleTrackIndexBeforeSetDataSource() {
+            assertTrue(nativeTestGetSampleTrackIndexBeforeSetDataSource());
+        }
+        private native boolean nativeTestGetSampleTrackIndexBeforeSetDataSource();
+
+        @Test
+        public void testGetSampleTrackIndexBeforeSelectTrack() {
+            assertTrue(
+                    nativeTestGetSampleTrackIndexBeforeSelectTrack(mInpPrefix + mInpMedia));
+        }
+        private native boolean nativeTestGetSampleTrackIndexBeforeSelectTrack(String srcPath);
+
+        @Test
+        public void testGetTrackFormatBeforeSetDataSource() {
+            assertTrue(nativeTestGetTrackFormatBeforeSetDataSource());
+        }
+        private native boolean nativeTestGetTrackFormatBeforeSetDataSource();
+
+        @Test
+        public void testGetTrackFormatForInvalidIndex() {
+            assertTrue(nativeTestGetTrackFormatForInvalidIndex(mInpPrefix + mInpMedia));
+        }
+        private native boolean nativeTestGetTrackFormatForInvalidIndex(String srcPath);
+
+        @Test
+        public void testReadSampleDataBeforeSetDataSource() {
+            assertTrue(nativeTestReadSampleDataBeforeSetDataSource());
+        }
+        private native boolean nativeTestReadSampleDataBeforeSetDataSource();
+
+        @Test
+        public void testReadSampleDataBeforeSelectTrack() {
+            assertTrue(nativeTestReadSampleDataBeforeSelectTrack(mInpPrefix + mInpMedia));
+        }
+        private native boolean nativeTestReadSampleDataBeforeSelectTrack(String srcPath);
+
+        @Test
+        public void testIfNullLocationIsRejectedBySetDataSource() {
+            assertTrue(nativeTestIfNullLocationIsRejectedBySetDataSource());
+        }
+        private native boolean nativeTestIfNullLocationIsRejectedBySetDataSource();
+    }
 }