From df63be71ce10a67bb7a3edfc7684b83822cd1f4c Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Thu, 18 Oct 2018 17:30:19 +0300 Subject: [android] Implement android test runner for core unit tests --- platform/android/config.cmake | 18 ++++---- platform/android/src/test/Main.java | 15 ------ platform/android/src/test/main.jni.cpp | 76 ------------------------------- platform/android/src/test/runtime.cpp | 73 +++++++++++++++++++++++++++++ platform/android/src/test/runtime.hpp | 9 ++++ platform/android/src/test/test_runner.cpp | 10 ++++ platform/android/src/test/version-script | 8 ++++ 7 files changed, 110 insertions(+), 99 deletions(-) delete mode 100644 platform/android/src/test/Main.java delete mode 100644 platform/android/src/test/main.jni.cpp create mode 100644 platform/android/src/test/runtime.cpp create mode 100644 platform/android/src/test/runtime.hpp create mode 100644 platform/android/src/test/test_runner.cpp create mode 100644 platform/android/src/test/version-script (limited to 'platform/android') diff --git a/platform/android/config.cmake b/platform/android/config.cmake index 4a2361a7db..d78a6ce94b 100644 --- a/platform/android/config.cmake +++ b/platform/android/config.cmake @@ -85,23 +85,25 @@ target_link_libraries(mapbox-gl PRIVATE mbgl-filesource ) -## Test library ## - -set(MBGL_TEST_TARGET_TYPE "library") +## Test executable ## macro(mbgl_platform_test) target_sources(mbgl-test - PRIVATE platform/default/src/mbgl/test/main.cpp - - # Main test entry point - platform/android/src/test/main.jni.cpp + PRIVATE platform/android/src/test/test_runner.cpp + PRIVATE platform/android/src/test/runtime.cpp ) target_include_directories(mbgl-test PRIVATE platform/android/include ) + set_target_properties(mbgl-test + PROPERTIES + LINK_FLAGS + "-fPIE -pie \ + -Wl,--export-dynamic \ + -Wl,--version-script=${CMAKE_SOURCE_DIR}/platform/android/src/test/version-script") + target_link_libraries(mbgl-test - PRIVATE mbgl-core PRIVATE mbgl-filesource ) endmacro() diff --git a/platform/android/src/test/Main.java b/platform/android/src/test/Main.java deleted file mode 100644 index b0f3aeb7b9..0000000000 --- a/platform/android/src/test/Main.java +++ /dev/null @@ -1,15 +0,0 @@ - -public class Main { - public native void runAllTests(String[] args); - - public static void main(String[] args) throws Exception { - // Load the tests - System.loadLibrary("mbgl-test"); - - // Run the tests - new Main().runAllTests(args); - - // Exit explicitly otherwise dalvikvm won't quit - System.exit(0); - } -} diff --git a/platform/android/src/test/main.jni.cpp b/platform/android/src/test/main.jni.cpp deleted file mode 100644 index 1cd0d26d2c..0000000000 --- a/platform/android/src/test/main.jni.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "../jni.hpp" - -#include - -#include -#include - -#include - -namespace { - -// Main class (entry point for tests from dalvikvm) -struct Main { - static constexpr auto Name() { - return "Main"; - } - - /** - * JNI Bound to Main#runAllTests() - */ - static void runAllTests(jni::JNIEnv& env, const jni::Object
&, const jni::Array& args) { - mbgl::Log::Warning(mbgl::Event::JNI, "Starting tests"); - - // We need to create a copy of the argv data since Java-internals are stored in UTF-16. - std::vector data; - // Add a fake first argument to align indices. Google Test expects the first argument to - // start at index 1; index 0 is the name of the executable. - data.push_back("main.jar"); - const int argc = args.Length(env); - for (auto i = 0; i < argc; i++) { - data.emplace_back(jni::Make(env, args.Get(env, i))); - } - - // Create an array of char pointers that point back to the data array. - std::vector argv; - for (const auto& arg : data) { - argv.push_back(arg.data()); - } - mbgl::runTests(argv.size(), const_cast(argv.data())); - } -}; - -} // namespace - -// We're declaring the function, which is libandroid_runtime.so. -// It is defined in AndroidRuntime.cpp: -// https://github.com/android/platform_frameworks_base/blob/master/core/jni/AndroidRuntime.cpp -// Once this symbol goes away, we'll have to revisit. -// This method loads and registers all of the Android-native frameworks so that we can use -// android.util.Log, android.graphics.Bitmap and so on. -// Setting the weak attribute tells the linker that this symbol is loaded at runtime and avoids -// a missing symbol error. -namespace android { -struct AndroidRuntime { - static int startReg(JNIEnv* env) __attribute__((weak)); -}; -} // namespace android - -// Main entry point -extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) { - // Load Android-native jni bindings - jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6); - android::AndroidRuntime::startReg(&env); - - // Load the main library jni bindings - mbgl::Log::Info(mbgl::Event::JNI, "Registering main JNI Methods"); - mbgl::android::registerNatives(vm); - - // Load the test library jni bindings - mbgl::Log::Info(mbgl::Event::JNI, "Registering test JNI Methods"); - - jni::RegisterNatives(env, *jni::Class
::Find(env), - jni::MakeNativeMethod("runAllTests")); - - return JNI_VERSION_1_6; -} diff --git a/platform/android/src/test/runtime.cpp b/platform/android/src/test/runtime.cpp new file mode 100644 index 0000000000..9cf79c501c --- /dev/null +++ b/platform/android/src/test/runtime.cpp @@ -0,0 +1,73 @@ +#include "runtime.hpp" +#include "../jni.hpp" + +#include +#include +#include +#include +#include + +// Required for art / libsigchain +extern "C" JNIEXPORT void EnsureFrontOfChain(int, struct sigaction*) { } +extern "C" JNIEXPORT void AddSpecialSignalHandlerFn(int, void*) { } +extern "C" JNIEXPORT void RemoveSpecialSignalHandlerFn(int, bool (*) (int, siginfo_t*, void*)) { } + +namespace { +const std::string kClassPathCommand{"--class_path="}; +const std::string kClassPath{"-Djava.class.path="}; +const std::string kDefaultDex{"/data/local/tmp/core-tests/classes.dex"}; +} // namespace + +namespace mbgl { +namespace android { + +bool initRuntime(int argc, char *argv[]) { + void* vmHandle = dlopen("libart.so", RTLD_NOW); + assert(vmHandle != nullptr); + + using CreateJavaVMFn = jint (*)(JavaVM** vm, JNIEnv** env, void* vmArgs); + CreateJavaVMFn createJavaVMFn = reinterpret_cast(dlsym(vmHandle, "JNI_CreateJavaVM")); + assert(createJavaVMFn != nullptr); + + std::string classPath = kClassPath + kDefaultDex; + for (int i = 0; i < argc; ++i) { + const std::string arg{argv[i]}; + if (arg.compare(0, kClassPathCommand.length(), kClassPathCommand) == 0) { + classPath = kClassPath + arg.substr(kClassPathCommand.length()); + break; + } + } + + JavaVMOption options[1]; + options[0].optionString = classPath.c_str(); + + JavaVMInitArgs args; + args.version = JNI_VERSION_1_6; + args.nOptions = 1; + args.options = options; + args.ignoreUnrecognized = JNI_FALSE; + + JavaVM* vm; + JNIEnv* env; + + if (createJavaVMFn(&vm, &env, &args) != JNI_OK) { + return false; + } + + void* runtimeHandle = dlopen("libandroid_runtime.so", RTLD_NOW); + assert(runtimeHandle != nullptr); + + using RegisterNativesFn = jint (*)(JNIEnv* env); + RegisterNativesFn registerNativesFn = reinterpret_cast(dlsym(runtimeHandle, "registerFrameworkNatives")); + assert(registerNativesFn != nullptr); + + if (registerNativesFn(env) != JNI_OK) { + return false; + } + + mbgl::android::registerNatives(vm); + return true; +} + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/test/runtime.hpp b/platform/android/src/test/runtime.hpp new file mode 100644 index 0000000000..c5e69d61c0 --- /dev/null +++ b/platform/android/src/test/runtime.hpp @@ -0,0 +1,9 @@ +#pragma once + +namespace mbgl { +namespace android { + +bool initRuntime(int argc, char *argv[]); + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/test/test_runner.cpp b/platform/android/src/test/test_runner.cpp new file mode 100644 index 0000000000..008e3c5748 --- /dev/null +++ b/platform/android/src/test/test_runner.cpp @@ -0,0 +1,10 @@ +#include "runtime.hpp" +#include + +int main(int argc, char *argv[]) { + if (!mbgl::android::initRuntime(argc, argv)) { + return 1; + } + + mbgl::runTests(argc, argv); +} diff --git a/platform/android/src/test/version-script b/platform/android/src/test/version-script new file mode 100644 index 0000000000..ebc2c17018 --- /dev/null +++ b/platform/android/src/test/version-script @@ -0,0 +1,8 @@ +{ +global: + EnsureFrontOfChain; + AddSpecialSignalHandlerFn; + RemoveSpecialSignalHandlerFn; +local: + *; +}; -- cgit v1.2.1