diff --git a/BUILD.gn b/BUILD.gn index 45069a45bd..10be0ca5c3 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -446,7 +446,14 @@ if (rtc_include_tests) { } if (is_android) { - deps += [ "//testing/android/native_test:native_test_support" ] + # Do not use Chromium's launcher. native_unittests defines its own JNI_OnLoad. + use_default_launcher = false + + deps += [ + "sdk/android:native_unittests", + "sdk/android:native_unittests_java", + "//testing/android/native_test:native_test_support", + ] shard_timeout = 900 } diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index 7a6c03636c..9225c6f497 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -892,3 +892,41 @@ rtc_static_library("native_api_codecs") { "//rtc_base:rtc_base_approved", ] } + +generate_jni("generated_native_unittests_jni") { + testonly = true + + sources = [ + "native_unittests/org/webrtc/JavaTypesTestHelper.java", + ] + jni_package = "" + jni_generator_include = "//sdk/android/src/jni/jni_generator_helper.h" +} + +rtc_android_library("native_unittests_java") { + testonly = true + + java_files = [ "native_unittests/org/webrtc/JavaTypesTestHelper.java" ] + + deps = [ + ":libjingle_peerconnection_java", + ] +} + +rtc_source_set("native_unittests") { + testonly = true + + sources = [ + "native_unittests/java_types_unittest.cc", + "native_unittests/test_jni_onload.cc", + ] + + deps = [ + ":generated_native_unittests_jni", + ":native_api_base", + ":native_api_jni", + "//rtc_base:checks", + "//test:test_support", + "//testing/gtest", + ] +} diff --git a/sdk/android/native_api/jni/java_types.cc b/sdk/android/native_api/jni/java_types.cc index 156925c48f..86ada91b1f 100644 --- a/sdk/android/native_api/jni/java_types.cc +++ b/sdk/android/native_api/jni/java_types.cc @@ -30,6 +30,8 @@ namespace webrtc { Iterable::Iterable(JNIEnv* jni, const JavaRef& iterable) : jni_(jni), iterable_(jni, iterable) {} +Iterable::Iterable(Iterable&& other) = default; + Iterable::~Iterable() = default; // Creates an iterator representing the end of any collection. @@ -103,6 +105,22 @@ std::string GetJavaEnumName(JNIEnv* jni, const JavaRef& j_enum) { return JavaToStdString(jni, JNI_Enum::Java_Enum_name(jni, j_enum)); } +Iterable GetJavaMapEntrySet(JNIEnv* jni, const JavaRef& j_map) { + return Iterable(jni, JNI_Map::Java_Map_entrySet(jni, j_map)); +} + +ScopedJavaLocalRef GetJavaMapEntryKey( + JNIEnv* jni, + const JavaRef& j_entry) { + return Java_JniHelper_getKey(jni, j_entry); +} + +ScopedJavaLocalRef GetJavaMapEntryValue( + JNIEnv* jni, + const JavaRef& j_entry) { + return Java_JniHelper_getValue(jni, j_entry); +} + int64_t JavaToNativeLong(JNIEnv* env, const JavaRef& j_long) { return JNI_Long::Java_Long_longValue(env, j_long); } @@ -136,6 +154,19 @@ std::string JavaToNativeString(JNIEnv* jni, const JavaRef& j_string) { return str; } +std::map JavaToNativeStringMap( + JNIEnv* jni, + const JavaRef& j_map) { + return JavaToNativeMap( + jni, j_map, + [](JNIEnv* env, JavaRef const& key, + JavaRef const& value) { + return std::make_pair( + JavaToNativeString(env, static_java_ref_cast(env, key)), + JavaToNativeString(env, static_java_ref_cast(env, value))); + }); +} + ScopedJavaLocalRef NativeToJavaBoolean(JNIEnv* env, bool b) { return JNI_Boolean::Java_Boolean_ConstructorJLB_Z(env, b); } @@ -242,18 +273,4 @@ std::vector JavaToStdVectorStrings(JNIEnv* jni, return converted_list; } -std::map JavaToStdMapStrings( - JNIEnv* jni, - const JavaRef& j_map) { - const JavaRef& j_entry_set = JNI_Map::Java_Map_entrySet(jni, j_map); - std::map result; - for (const JavaRef& j_entry : Iterable(jni, j_entry_set)) { - result.insert(std::make_pair( - JavaToStdString(jni, Java_JniHelper_getKey(jni, j_entry)), - JavaToStdString(jni, Java_JniHelper_getValue(jni, j_entry)))); - } - - return result; -} - } // namespace webrtc diff --git a/sdk/android/native_api/jni/java_types.h b/sdk/android/native_api/jni/java_types.h index 2f5e8f84f3..d9d2b1a3e5 100644 --- a/sdk/android/native_api/jni/java_types.h +++ b/sdk/android/native_api/jni/java_types.h @@ -50,6 +50,8 @@ namespace webrtc { class Iterable { public: Iterable(JNIEnv* jni, const JavaRef& iterable); + Iterable(Iterable&& other); + ~Iterable(); class Iterator { @@ -111,6 +113,13 @@ bool IsNull(JNIEnv* jni, const JavaRef& obj); // Returns the name of a Java enum. std::string GetJavaEnumName(JNIEnv* jni, const JavaRef& j_enum); +Iterable GetJavaMapEntrySet(JNIEnv* jni, const JavaRef& j_map); +ScopedJavaLocalRef GetJavaMapEntryKey(JNIEnv* jni, + const JavaRef& j_entry); +ScopedJavaLocalRef GetJavaMapEntryValue( + JNIEnv* jni, + const JavaRef& j_entry); + // -------------------------------------------------------- // -- Methods for converting Java types to native types. -- // -------------------------------------------------------- @@ -141,6 +150,23 @@ std::vector JavaToNativeVector(JNIEnv* env, return container; } +template +std::map JavaToNativeMap(JNIEnv* env, + const JavaRef& j_map, + Convert convert) { + std::map container; + for (auto const& j_entry : GetJavaMapEntrySet(env, j_map)) { + container.emplace(convert(env, GetJavaMapEntryKey(env, j_entry), + GetJavaMapEntryValue(env, j_entry))); + } + return container; +} + +// Converts Map to std::map. +std::map JavaToNativeStringMap( + JNIEnv* env, + const JavaRef& j_map); + // -------------------------------------------------------- // -- Methods for converting native types to Java types. -- // -------------------------------------------------------- @@ -262,10 +288,13 @@ inline std::string JavaToStdString(JNIEnv* jni, jstring j_string) { std::vector JavaToStdVectorStrings(JNIEnv* jni, const JavaRef& list); +// Deprecated. Use JavaToNativeStringMap instead. // Parses Map to std::map. -std::map JavaToStdMapStrings( +inline std::map JavaToStdMapStrings( JNIEnv* jni, - const JavaRef& j_map); + const JavaRef& j_map) { + return JavaToNativeStringMap(jni, j_map); +} // Deprecated. Use scoped jobjects instead. inline std::map JavaToStdMapStrings(JNIEnv* jni, diff --git a/sdk/android/native_api/jni/scoped_java_ref.h b/sdk/android/native_api/jni/scoped_java_ref.h index e3259f1d8a..02948e091e 100644 --- a/sdk/android/native_api/jni/scoped_java_ref.h +++ b/sdk/android/native_api/jni/scoped_java_ref.h @@ -197,6 +197,13 @@ class ScopedJavaGlobalRef : public JavaRef { RTC_DISALLOW_COPY_AND_ASSIGN(ScopedJavaGlobalRef); }; +template +inline ScopedJavaLocalRef static_java_ref_cast(JNIEnv* env, + JavaRef const& ref) { + ScopedJavaLocalRef owned_ref(env, ref); + return ScopedJavaLocalRef(env, static_cast(owned_ref.Release())); +} + } // namespace webrtc #endif // SDK_ANDROID_NATIVE_API_JNI_SCOPED_JAVA_REF_H_ diff --git a/sdk/android/native_unittests/java_types_unittest.cc b/sdk/android/native_unittests/java_types_unittest.cc new file mode 100644 index 0000000000..a549e03ca4 --- /dev/null +++ b/sdk/android/native_unittests/java_types_unittest.cc @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include + +#include "sdk/android/generated_native_unittests_jni/jni/JavaTypesTestHelper_jni.h" +#include "sdk/android/native_api/jni/java_types.h" +#include "test/gtest.h" + +namespace webrtc { +namespace test { +namespace { +TEST(JavaTypesTest, TestJavaToNativeStringMap) { + JNIEnv* env = AttachCurrentThreadIfNeeded(); + ScopedJavaLocalRef j_map = + Java_JavaTypesTestHelper_createTestStringMap(env); + + std::map output = JavaToNativeStringMap(env, j_map); + + std::map expected{ + {"one", "1"}, {"two", "2"}, {"three", "3"}, + }; + EXPECT_EQ(expected, output); +} +} // namespace +} // namespace test +} // namespace webrtc diff --git a/sdk/android/native_unittests/org/webrtc/JavaTypesTestHelper.java b/sdk/android/native_unittests/org/webrtc/JavaTypesTestHelper.java new file mode 100644 index 0000000000..6695ef79af --- /dev/null +++ b/sdk/android/native_unittests/org/webrtc/JavaTypesTestHelper.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc; + +import java.util.HashMap; +import java.util.Map; + +public class JavaTypesTestHelper { + @CalledByNative + public static Map createTestStringMap() { + Map testMap = new HashMap(); + testMap.put("one", "1"); + testMap.put("two", "2"); + testMap.put("three", "3"); + return testMap; + } +} diff --git a/sdk/android/native_unittests/test_jni_onload.cc b/sdk/android/native_unittests/test_jni_onload.cc new file mode 100644 index 0000000000..dafe49c474 --- /dev/null +++ b/sdk/android/native_unittests/test_jni_onload.cc @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#undef JNIEXPORT +#define JNIEXPORT __attribute__((visibility("default"))) + +#include "rtc_base/checks.h" +#include "sdk/android/native_api/base/init.h" +#include "sdk/android/native_api/jni/java_types.h" + +// This is called by the VM when the shared library is first loaded. +JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { + webrtc::InitAndroid(vm); + return JNI_VERSION_1_4; +} diff --git a/sdk/android/src/java/org/webrtc/JniHelper.java b/sdk/android/src/java/org/webrtc/JniHelper.java index 5b00ffef11..0d56d5d92b 100644 --- a/sdk/android/src/java/org/webrtc/JniHelper.java +++ b/sdk/android/src/java/org/webrtc/JniHelper.java @@ -36,13 +36,13 @@ class JniHelper { // TODO(bugs.webrtc.org/8606): Remove. @CalledByNative - static String getKey(Map.Entry entry) { + static Object getKey(Map.Entry entry) { return entry.getKey(); } // TODO(bugs.webrtc.org/8606): Remove. @CalledByNative - static String getValue(Map.Entry entry) { + static Object getValue(Map.Entry entry) { return entry.getValue(); } } diff --git a/sdk/android/src/jni/hardwarevideoencoderfactory.cc b/sdk/android/src/jni/hardwarevideoencoderfactory.cc index ebd9b0afa6..6404c189d6 100644 --- a/sdk/android/src/jni/hardwarevideoencoderfactory.cc +++ b/sdk/android/src/jni/hardwarevideoencoderfactory.cc @@ -23,8 +23,8 @@ static jboolean JNI_HardwareVideoEncoderFactory_IsSameH264Profile( const JavaParamRef&, const JavaParamRef& params1, const JavaParamRef& params2) { - return H264::IsSameH264Profile(JavaToStdMapStrings(jni, params1), - JavaToStdMapStrings(jni, params2)); + return H264::IsSameH264Profile(JavaToNativeStringMap(jni, params1), + JavaToNativeStringMap(jni, params2)); } } // namespace jni diff --git a/sdk/android/src/jni/videocodecinfo.cc b/sdk/android/src/jni/videocodecinfo.cc index 0ddc3287f0..e467e5fbe4 100644 --- a/sdk/android/src/jni/videocodecinfo.cc +++ b/sdk/android/src/jni/videocodecinfo.cc @@ -20,8 +20,8 @@ namespace jni { SdpVideoFormat VideoCodecInfoToSdpVideoFormat(JNIEnv* jni, const JavaRef& j_info) { return SdpVideoFormat( - JavaToStdString(jni, Java_VideoCodecInfo_getName(jni, j_info)), - JavaToStdMapStrings(jni, Java_VideoCodecInfo_getParams(jni, j_info))); + JavaToNativeString(jni, Java_VideoCodecInfo_getName(jni, j_info)), + JavaToNativeStringMap(jni, Java_VideoCodecInfo_getParams(jni, j_info))); } ScopedJavaLocalRef SdpVideoFormatToVideoCodecInfo(