From 72045da4beec0fd45f49decbc75561a1116dabf4 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Fri, 15 Jun 2018 15:55:10 +0100 Subject: [PATCH] Use the latest fbjni --- build.gradle | 2 + libs/fbjni/ApplicationManifest.xml | 4 + libs/fbjni/BUCK | 86 +++- libs/fbjni/CMakeLists.txt | 41 ++ libs/fbjni/build.gradle | 14 +- .../main/cpp/jni => cxx/fbjni}/ByteBuffer.cpp | 26 +- libs/fbjni/cxx/fbjni/ByteBuffer.h | 45 ++ libs/fbjni/cxx/fbjni/Context.h | 42 ++ libs/fbjni/cxx/fbjni/File.h | 37 ++ libs/fbjni/cxx/fbjni/JThread.h | 66 +++ .../include/fb => cxx}/fbjni/NativeRunnable.h | 21 +- libs/fbjni/cxx/fbjni/OnLoad.cpp | 28 ++ libs/fbjni/cxx/fbjni/ReadableByteChannel.cpp | 31 ++ libs/fbjni/cxx/fbjni/ReadableByteChannel.h | 32 ++ .../fb/fbjni => cxx/fbjni/detail}/Boxed.h | 28 +- .../fb/fbjni => cxx/fbjni/detail}/Common.h | 40 +- .../fbjni/detail}/CoreClasses-inl.h | 117 +++-- .../fbjni => cxx/fbjni/detail}/CoreClasses.h | 118 +++--- libs/fbjni/cxx/fbjni/detail/Environment.cpp | 301 +++++++++++++ .../fb => cxx/fbjni/detail}/Environment.h | 85 +++- libs/fbjni/cxx/fbjni/detail/Exceptions.cpp | 400 ++++++++++++++++++ .../fbjni => cxx/fbjni/detail}/Exceptions.h | 44 +- libs/fbjni/cxx/fbjni/detail/Hybrid.cpp | 42 ++ .../fb/fbjni => cxx/fbjni/detail}/Hybrid.h | 112 +++-- .../fbjni => cxx/fbjni/detail}/Iterator-inl.h | 19 +- .../fb/fbjni => cxx/fbjni/detail}/Iterator.h | 17 +- libs/fbjni/cxx/fbjni/detail/JWeakReference.h | 49 +++ libs/fbjni/cxx/fbjni/detail/Log.h | 77 ++++ libs/fbjni/cxx/fbjni/detail/Meta-forward.h | 43 ++ .../fb/fbjni => cxx/fbjni/detail}/Meta-inl.h | 110 ++--- .../fb/fbjni => cxx/fbjni/detail}/Meta.h | 23 +- .../fbjni => cxx/fbjni/detail}/MetaConvert.h | 32 +- .../fbjni/detail}/ReferenceAllocators-inl.h | 58 ++- .../cxx/fbjni/detail/ReferenceAllocators.h | 64 +++ .../fbjni/detail}/References-forward.h | 17 +- .../fbjni/detail}/References-inl.h | 32 +- libs/fbjni/cxx/fbjni/detail/References.cpp | 75 ++++ .../fbjni => cxx/fbjni/detail}/References.h | 27 +- .../fbjni/cxx/fbjni/detail/Registration-inl.h | 156 +++++++ .../fbjni => cxx/fbjni/detail}/Registration.h | 31 +- .../fbjni => cxx/fbjni/detail}/TypeTraits.h | 17 +- .../fbjni/detail/utf8.cpp} | 88 ++-- .../LocalString.h => cxx/fbjni/detail/utf8.h} | 53 ++- .../{src/main/cpp/jni => cxx/fbjni}/fbjni.cpp | 132 ++++-- libs/fbjni/cxx/fbjni/fbjni.h | 32 ++ libs/fbjni/cxx/lyra/cxa_throw.cpp | 116 +++++ .../fbjni/{src/main/cpp => cxx}/lyra/lyra.cpp | 70 ++- .../main/cpp/include/fb => cxx/lyra}/lyra.h | 71 +++- libs/fbjni/cxx/lyra/lyra_breakpad.cpp | 32 ++ libs/fbjni/cxx/lyra/lyra_exceptions.cpp | 98 +++++ libs/fbjni/cxx/lyra/lyra_exceptions.h | 94 ++++ .../java/com/facebook/jni/CppException.java | 27 ++ .../facebook/jni/CppSystemErrorException.java | 34 ++ .../com/facebook/jni/DestructorThread.java | 148 +++++++ .../com/facebook/jni/HybridClassBase.java | 22 + .../java/com/facebook/jni/HybridData.java | 87 ++++ .../java/com/facebook/jni/IteratorHelper.java | 58 +++ .../com/facebook/jni/MapIteratorHelper.java | 57 +++ .../java/com/facebook/jni/NativeRunnable.java | 31 ++ .../com/facebook/jni/ThreadScopeSupport.java | 36 ++ .../com/facebook/jni/UnknownCppException.java | 32 ++ .../facebook/jni/annotations/DoNotStrip.java | 33 ++ libs/fbjni/src/main/AndroidManifest.xml | 14 - libs/fbjni/src/main/cpp/CMakeLists.txt | 33 -- libs/fbjni/src/main/cpp/assert.cpp | 39 -- libs/fbjni/src/main/cpp/include/fb/ALog.h | 81 ---- .../fbjni/src/main/cpp/include/fb/Countable.h | 45 -- libs/fbjni/src/main/cpp/include/fb/Doxyfile | 18 - .../src/main/cpp/include/fb/ProgramLocation.h | 48 --- libs/fbjni/src/main/cpp/include/fb/RefPtr.h | 272 ------------ .../main/cpp/include/fb/StaticInitialized.h | 38 -- .../src/main/cpp/include/fb/ThreadLocal.h | 116 ----- libs/fbjni/src/main/cpp/include/fb/assert.h | 34 -- libs/fbjni/src/main/cpp/include/fb/fbjni.h | 23 - .../main/cpp/include/fb/fbjni/ByteBuffer.h | 32 -- .../src/main/cpp/include/fb/fbjni/Context.h | 33 -- .../src/main/cpp/include/fb/fbjni/File.h | 28 -- .../src/main/cpp/include/fb/fbjni/JThread.h | 37 -- .../main/cpp/include/fb/fbjni/JThrowable.h | 14 - .../main/cpp/include/fb/fbjni/Meta-forward.h | 34 -- .../include/fb/fbjni/ReferenceAllocators.h | 60 --- .../cpp/include/fb/fbjni/Registration-inl.h | 184 -------- libs/fbjni/src/main/cpp/include/fb/log.h | 346 --------------- .../src/main/cpp/include/fb/noncopyable.h | 19 - .../src/main/cpp/include/fb/nonmovable.h | 19 - .../src/main/cpp/include/fb/visibility.h | 10 - .../src/main/cpp/include/jni/Countable.h | 34 -- .../main/cpp/include/jni/GlobalReference.h | 89 ---- .../src/main/cpp/include/jni/LocalReference.h | 35 -- .../src/main/cpp/include/jni/Registration.h | 25 -- .../src/main/cpp/include/jni/WeakReference.h | 53 --- .../src/main/cpp/include/jni/jni_helpers.h | 137 ------ libs/fbjni/src/main/cpp/jni/Countable.cpp | 67 --- libs/fbjni/src/main/cpp/jni/Environment.cpp | 130 ------ libs/fbjni/src/main/cpp/jni/Exceptions.cpp | 283 ------------- libs/fbjni/src/main/cpp/jni/Hybrid.cpp | 63 --- libs/fbjni/src/main/cpp/jni/JThrowable.cpp | 23 - libs/fbjni/src/main/cpp/jni/OnLoad.cpp | 20 - libs/fbjni/src/main/cpp/jni/References.cpp | 39 -- libs/fbjni/src/main/cpp/jni/WeakReference.cpp | 41 -- libs/fbjni/src/main/cpp/jni/jni_helpers.cpp | 195 --------- libs/fbjni/src/main/cpp/log.cpp | 98 ----- libs/fbjni/src/main/cpp/onload.cpp | 29 -- .../fbjni/src/main/java/com/facebook/jni/BUCK | 20 - .../main/java/com/facebook/jni/Countable.java | 30 -- .../java/com/facebook/jni/CppException.java | 18 - .../facebook/jni/CppSystemErrorException.java | 25 -- .../com/facebook/jni/HybridClassBase.java | 11 - .../java/com/facebook/jni/HybridData.java | 44 -- .../java/com/facebook/jni/IteratorHelper.java | 54 --- .../com/facebook/jni/MapIteratorHelper.java | 51 --- .../java/com/facebook/jni/NativeRunnable.java | 26 -- .../com/facebook/jni/ThreadScopeSupport.java | 17 - .../com/facebook/jni/UnknownCppException.java | 23 - .../src/main/java/com/facebook/jni/fbjni.pro | 11 - 115 files changed, 3444 insertions(+), 3784 deletions(-) create mode 100644 libs/fbjni/ApplicationManifest.xml create mode 100644 libs/fbjni/CMakeLists.txt rename libs/fbjni/{src/main/cpp/jni => cxx/fbjni}/ByteBuffer.cpp (72%) create mode 100644 libs/fbjni/cxx/fbjni/ByteBuffer.h create mode 100644 libs/fbjni/cxx/fbjni/Context.h create mode 100644 libs/fbjni/cxx/fbjni/File.h create mode 100644 libs/fbjni/cxx/fbjni/JThread.h rename libs/fbjni/{src/main/cpp/include/fb => cxx}/fbjni/NativeRunnable.h (52%) create mode 100644 libs/fbjni/cxx/fbjni/OnLoad.cpp create mode 100644 libs/fbjni/cxx/fbjni/ReadableByteChannel.cpp create mode 100644 libs/fbjni/cxx/fbjni/ReadableByteChannel.h rename libs/fbjni/{src/main/cpp/include/fb/fbjni => cxx/fbjni/detail}/Boxed.h (67%) rename libs/fbjni/{src/main/cpp/include/fb/fbjni => cxx/fbjni/detail}/Common.h (70%) rename libs/fbjni/{src/main/cpp/include/fb/fbjni => cxx/fbjni/detail}/CoreClasses-inl.h (85%) rename libs/fbjni/{src/main/cpp/include/fb/fbjni => cxx/fbjni/detail}/CoreClasses.h (90%) create mode 100644 libs/fbjni/cxx/fbjni/detail/Environment.cpp rename libs/fbjni/{src/main/cpp/include/fb => cxx/fbjni/detail}/Environment.h (50%) create mode 100644 libs/fbjni/cxx/fbjni/detail/Exceptions.cpp rename libs/fbjni/{src/main/cpp/include/fb/fbjni => cxx/fbjni/detail}/Exceptions.h (70%) create mode 100644 libs/fbjni/cxx/fbjni/detail/Hybrid.cpp rename libs/fbjni/{src/main/cpp/include/fb/fbjni => cxx/fbjni/detail}/Hybrid.h (67%) rename libs/fbjni/{src/main/cpp/include/fb/fbjni => cxx/fbjni/detail}/Iterator-inl.h (89%) rename libs/fbjni/{src/main/cpp/include/fb/fbjni => cxx/fbjni/detail}/Iterator.h (87%) create mode 100644 libs/fbjni/cxx/fbjni/detail/JWeakReference.h create mode 100644 libs/fbjni/cxx/fbjni/detail/Log.h create mode 100644 libs/fbjni/cxx/fbjni/detail/Meta-forward.h rename libs/fbjni/{src/main/cpp/include/fb/fbjni => cxx/fbjni/detail}/Meta-inl.h (84%) rename libs/fbjni/{src/main/cpp/include/fb/fbjni => cxx/fbjni/detail}/Meta.h (93%) rename libs/fbjni/{src/main/cpp/include/fb/fbjni => cxx/fbjni/detail}/MetaConvert.h (64%) rename libs/fbjni/{src/main/cpp/include/fb/fbjni => cxx/fbjni/detail}/ReferenceAllocators-inl.h (61%) create mode 100644 libs/fbjni/cxx/fbjni/detail/ReferenceAllocators.h rename libs/fbjni/{src/main/cpp/include/fb/fbjni => cxx/fbjni/detail}/References-forward.h (69%) rename libs/fbjni/{src/main/cpp/include/fb/fbjni => cxx/fbjni/detail}/References-inl.h (92%) create mode 100644 libs/fbjni/cxx/fbjni/detail/References.cpp rename libs/fbjni/{src/main/cpp/include/fb/fbjni => cxx/fbjni/detail}/References.h (96%) create mode 100644 libs/fbjni/cxx/fbjni/detail/Registration-inl.h rename libs/fbjni/{src/main/cpp/include/fb/fbjni => cxx/fbjni/detail}/Registration.h (76%) rename libs/fbjni/{src/main/cpp/include/fb/fbjni => cxx/fbjni/detail}/TypeTraits.h (88%) rename libs/fbjni/{src/main/cpp/jni/LocalString.cpp => cxx/fbjni/detail/utf8.cpp} (76%) rename libs/fbjni/{src/main/cpp/include/jni/LocalString.h => cxx/fbjni/detail/utf8.h} (68%) rename libs/fbjni/{src/main/cpp/jni => cxx/fbjni}/fbjni.cpp (64%) create mode 100644 libs/fbjni/cxx/fbjni/fbjni.h create mode 100644 libs/fbjni/cxx/lyra/cxa_throw.cpp rename libs/fbjni/{src/main/cpp => cxx}/lyra/lyra.cpp (58%) rename libs/fbjni/{src/main/cpp/include/fb => cxx/lyra}/lyra.h (67%) create mode 100644 libs/fbjni/cxx/lyra/lyra_breakpad.cpp create mode 100644 libs/fbjni/cxx/lyra/lyra_exceptions.cpp create mode 100644 libs/fbjni/cxx/lyra/lyra_exceptions.h create mode 100644 libs/fbjni/java/com/facebook/jni/CppException.java create mode 100644 libs/fbjni/java/com/facebook/jni/CppSystemErrorException.java create mode 100644 libs/fbjni/java/com/facebook/jni/DestructorThread.java create mode 100644 libs/fbjni/java/com/facebook/jni/HybridClassBase.java create mode 100644 libs/fbjni/java/com/facebook/jni/HybridData.java create mode 100644 libs/fbjni/java/com/facebook/jni/IteratorHelper.java create mode 100644 libs/fbjni/java/com/facebook/jni/MapIteratorHelper.java create mode 100644 libs/fbjni/java/com/facebook/jni/NativeRunnable.java create mode 100644 libs/fbjni/java/com/facebook/jni/ThreadScopeSupport.java create mode 100644 libs/fbjni/java/com/facebook/jni/UnknownCppException.java create mode 100644 libs/fbjni/java/com/facebook/jni/annotations/DoNotStrip.java delete mode 100644 libs/fbjni/src/main/AndroidManifest.xml delete mode 100644 libs/fbjni/src/main/cpp/CMakeLists.txt delete mode 100644 libs/fbjni/src/main/cpp/assert.cpp delete mode 100644 libs/fbjni/src/main/cpp/include/fb/ALog.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/Countable.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/Doxyfile delete mode 100644 libs/fbjni/src/main/cpp/include/fb/ProgramLocation.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/RefPtr.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/StaticInitialized.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/ThreadLocal.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/assert.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/fbjni.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/fbjni/ByteBuffer.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/fbjni/Context.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/fbjni/File.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/fbjni/JThread.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/fbjni/JThrowable.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/fbjni/Meta-forward.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/fbjni/ReferenceAllocators.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/fbjni/Registration-inl.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/log.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/noncopyable.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/nonmovable.h delete mode 100644 libs/fbjni/src/main/cpp/include/fb/visibility.h delete mode 100644 libs/fbjni/src/main/cpp/include/jni/Countable.h delete mode 100644 libs/fbjni/src/main/cpp/include/jni/GlobalReference.h delete mode 100644 libs/fbjni/src/main/cpp/include/jni/LocalReference.h delete mode 100644 libs/fbjni/src/main/cpp/include/jni/Registration.h delete mode 100644 libs/fbjni/src/main/cpp/include/jni/WeakReference.h delete mode 100644 libs/fbjni/src/main/cpp/include/jni/jni_helpers.h delete mode 100644 libs/fbjni/src/main/cpp/jni/Countable.cpp delete mode 100644 libs/fbjni/src/main/cpp/jni/Environment.cpp delete mode 100644 libs/fbjni/src/main/cpp/jni/Exceptions.cpp delete mode 100644 libs/fbjni/src/main/cpp/jni/Hybrid.cpp delete mode 100644 libs/fbjni/src/main/cpp/jni/JThrowable.cpp delete mode 100644 libs/fbjni/src/main/cpp/jni/OnLoad.cpp delete mode 100644 libs/fbjni/src/main/cpp/jni/References.cpp delete mode 100644 libs/fbjni/src/main/cpp/jni/WeakReference.cpp delete mode 100644 libs/fbjni/src/main/cpp/jni/jni_helpers.cpp delete mode 100644 libs/fbjni/src/main/cpp/log.cpp delete mode 100644 libs/fbjni/src/main/cpp/onload.cpp delete mode 100644 libs/fbjni/src/main/java/com/facebook/jni/BUCK delete mode 100644 libs/fbjni/src/main/java/com/facebook/jni/Countable.java delete mode 100644 libs/fbjni/src/main/java/com/facebook/jni/CppException.java delete mode 100644 libs/fbjni/src/main/java/com/facebook/jni/CppSystemErrorException.java delete mode 100644 libs/fbjni/src/main/java/com/facebook/jni/HybridClassBase.java delete mode 100644 libs/fbjni/src/main/java/com/facebook/jni/HybridData.java delete mode 100644 libs/fbjni/src/main/java/com/facebook/jni/IteratorHelper.java delete mode 100644 libs/fbjni/src/main/java/com/facebook/jni/MapIteratorHelper.java delete mode 100644 libs/fbjni/src/main/java/com/facebook/jni/NativeRunnable.java delete mode 100644 libs/fbjni/src/main/java/com/facebook/jni/ThreadScopeSupport.java delete mode 100644 libs/fbjni/src/main/java/com/facebook/jni/UnknownCppException.java delete mode 100644 libs/fbjni/src/main/java/com/facebook/jni/fbjni.pro diff --git a/build.gradle b/build.gradle index 6a444bec6..f18058433 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,8 @@ subprojects { repositories { jcenter() google() + mavenLocal() + mavenCentral() } } diff --git a/libs/fbjni/ApplicationManifest.xml b/libs/fbjni/ApplicationManifest.xml new file mode 100644 index 000000000..d09d5f057 --- /dev/null +++ b/libs/fbjni/ApplicationManifest.xml @@ -0,0 +1,4 @@ + + + diff --git a/libs/fbjni/BUCK b/libs/fbjni/BUCK index d44100c42..43eee3b67 100644 --- a/libs/fbjni/BUCK +++ b/libs/fbjni/BUCK @@ -1,9 +1,81 @@ -# BUILD FILE SYNTAX: SKYLARK -# Copyright (c) 2017-present, Facebook, Inc. -# -# This source code is licensed under the Apache 2.0 license found in the -# LICENSE file in the root directory of this source tree. +load("//build_defs:fb_xplat_cxx_library.bzl", "fb_xplat_cxx_library") +load("@xplat//build_defs:fb_java_library.bzl", "fb_java_library") -load("//:LITHO_DEFS.bzl", "define_fbjni_targets") +ANNOTATIONS_SRCS = [ + "java/com/facebook/jni/annotations/*.java", +] -define_fbjni_targets() +fb_java_library( + name = "java_annotations", + srcs = glob(ANNOTATIONS_SRCS), + required_for_source_only_abi = True, +) + +fb_java_library( + name = "java", + srcs = glob( + ["java/**/*.java"], + exclude = ANNOTATIONS_SRCS, + ), + required_for_source_only_abi = True, + visibility = ["PUBLIC"], + deps = [ + "//libraries/soloader/java/com/facebook/soloader:soloader", + "//third-party/java/jsr-305:jsr-305", + ], + exported_deps = [ + ":java_annotations", + ], +) + +fb_xplat_cxx_library( + name = "fbjni", + srcs = glob([ + "cxx/fbjni/**/*.cpp", + ]), + header_namespace = "", + exported_headers = subdir_glob([ + ("cxx", "fbjni/**/*.h"), + ]), + allow_jni_merging = True, + compiler_flags = [ + "-fexceptions", + "-fno-omit-frame-pointer", + "-frtti", + "-ffunction-sections", + ], + enable_static_variant = True, + exported_platform_headers = [ + ( + "^(?!android-arm$).*$", + subdir_glob([ + ("cxx", "lyra/**/*.h"), + ]), + ), + ], + fbandroid_deps = [ + "xplat//third-party/linker_lib:atomic", + ], + platform_srcs = [ + ( + "^(?!android-arm$).*$", + glob([ + "cxx/lyra/*.cpp", + ]), + ), + ], + preprocessor_flags = [ + "-DLOG_TAG=\"libfbjni\"", + ], + soname = "libfbjni.$(ext)", + visibility = [ + "PUBLIC", + ], + deps = [ + "xplat//third-party/linker_lib:android", + ], + exported_deps = [ + "xplat//third-party/linker_lib:log", + "//native/jni-hack:jni-hack", + ], +) diff --git a/libs/fbjni/CMakeLists.txt b/libs/fbjni/CMakeLists.txt new file mode 100644 index 000000000..ea30a3aee --- /dev/null +++ b/libs/fbjni/CMakeLists.txt @@ -0,0 +1,41 @@ +# +# Copyright (c) 2014-present, Facebook, Inc. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +# + +cmake_minimum_required(VERSION 3.6.0) + +set(CMAKE_VERBOSE_MAKEFILE on) + +add_compile_options( + -fno-omit-frame-pointer + -fexceptions + -Wall + -std=c++11 + -DDISABLE_CPUCAP + -DDISABLE_XPLAT) + +set(FBJNI_CXX ${PROJECT_SOURCE_DIR}/cxx) + +list(APPEND FBJNI_HDRS ${FBJNI_CXX}) +list(APPEND FBJNI_HDRS ${FBJNI_CXX}/fbjni/) +list(APPEND FBJNI_HDRS ${FBJNI_CXX}/fbjni/detail) +list(APPEND FBJNI_HDRS ${FBJNI_CXX}/lyra) +include_directories(${FBJNI_HDRS}) + +message(STATUS "FBJNI_HDRS =>" ${FBJNI_HDRS}) +file(GLOB FBJNI_SRC + ${FBJNI_CXX}/fbjni/*.cpp + ${FBJNI_CXX}/fbjni/detail/*.cpp + ${FBJNI_CXX}/lyra/*.cpp) + + +add_library(fb SHARED + ${FBJNI_SRC}) + +#target_include_directories(fb PRIVATE +# include ${libjnihack_DIR}) + +target_link_libraries(fb log) diff --git a/libs/fbjni/build.gradle b/libs/fbjni/build.gradle index 812e34e27..1c80c38fe 100644 --- a/libs/fbjni/build.gradle +++ b/libs/fbjni/build.gradle @@ -7,9 +7,16 @@ android { defaultConfig { minSdkVersion rootProject.minSdkVersion targetSdkVersion rootProject.targetSdkVersion - + sourceSets { + main { + manifest.srcFile './ApplicationManifest.xml' + java { + srcDir 'java' + } + } + } ndk { - abiFilters 'arm64-v8a', 'x86' + abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' } externalNativeBuild { @@ -20,7 +27,7 @@ android { } externalNativeBuild { cmake { - path './src/main/cpp/CMakeLists.txt' + path './CMakeLists.txt' } } } @@ -30,4 +37,5 @@ dependencies { compileOnly deps.jsr305 compileOnly deps.inferAnnotations compileOnly 'com.facebook.litho:litho-annotations:0.15.0' + compileOnly 'com.facebook.soloader:soloader:0.5.0' } diff --git a/libs/fbjni/src/main/cpp/jni/ByteBuffer.cpp b/libs/fbjni/cxx/fbjni/ByteBuffer.cpp similarity index 72% rename from libs/fbjni/src/main/cpp/jni/ByteBuffer.cpp rename to libs/fbjni/cxx/fbjni/ByteBuffer.cpp index 5a5317f9f..82060d74d 100644 --- a/libs/fbjni/src/main/cpp/jni/ByteBuffer.cpp +++ b/libs/fbjni/cxx/fbjni/ByteBuffer.cpp @@ -1,16 +1,23 @@ -/* - * Copyright (c) 2016-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ -#include +#include #include -#include - namespace facebook { namespace jni { @@ -22,6 +29,11 @@ local_ref createEmpty() { } } +void JBuffer::rewind() const { + static auto meth = javaClassStatic()->getMethod()>("rewind"); + meth(self()); +} + local_ref JByteBuffer::wrapBytes(uint8_t* data, size_t size) { // env->NewDirectByteBuffer requires that size is positive. Android's // dalvik returns an invalid result and Android's art aborts if size == 0. diff --git a/libs/fbjni/cxx/fbjni/ByteBuffer.h b/libs/fbjni/cxx/fbjni/ByteBuffer.h new file mode 100644 index 000000000..91beff2f5 --- /dev/null +++ b/libs/fbjni/cxx/fbjni/ByteBuffer.h @@ -0,0 +1,45 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +#pragma once + +#include + +namespace facebook { +namespace jni { + +class JBuffer : public JavaClass { +public: + static constexpr const char* kJavaDescriptor = "Ljava/nio/Buffer;"; + + void rewind() const; +}; + +// JNI's NIO support has some awkward preconditions and error reporting. This +// class provides much more user-friendly access. +class JByteBuffer : public JavaClass { + public: + static constexpr const char* kJavaDescriptor = "Ljava/nio/ByteBuffer;"; + + static local_ref wrapBytes(uint8_t* data, size_t size); + + bool isDirect() const; + + uint8_t* getDirectBytes() const; + size_t getDirectSize() const; +}; + +}} diff --git a/libs/fbjni/cxx/fbjni/Context.h b/libs/fbjni/cxx/fbjni/Context.h new file mode 100644 index 000000000..ca75972fd --- /dev/null +++ b/libs/fbjni/cxx/fbjni/Context.h @@ -0,0 +1,42 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +#pragma once + +#include +#include + +namespace facebook { +namespace jni { + +class AContext : public JavaClass { + public: + static constexpr const char* kJavaDescriptor = "Landroid/content/Context;"; + + // Define a method that calls into the represented Java class + local_ref getCacheDir() { + static const auto method = getClass()->getMethod("getCacheDir"); + return method(self()); + } + + local_ref getFilesDir() { + static const auto method = getClass()->getMethod("getFilesDir"); + return method(self()); + } +}; + +} +} diff --git a/libs/fbjni/cxx/fbjni/File.h b/libs/fbjni/cxx/fbjni/File.h new file mode 100644 index 000000000..f9966c6ae --- /dev/null +++ b/libs/fbjni/cxx/fbjni/File.h @@ -0,0 +1,37 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +#pragma once + +#include + +namespace facebook { +namespace jni { + +class JFile : public JavaClass { + public: + static constexpr const char* kJavaDescriptor = "Ljava/io/File;"; + + // Define a method that calls into the represented Java class + std::string getAbsolutePath() { + static const auto method = getClass()->getMethod("getAbsolutePath"); + return method(self())->toStdString(); + } + +}; + +} +} diff --git a/libs/fbjni/cxx/fbjni/JThread.h b/libs/fbjni/cxx/fbjni/JThread.h new file mode 100644 index 000000000..6bdb269f2 --- /dev/null +++ b/libs/fbjni/cxx/fbjni/JThread.h @@ -0,0 +1,66 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +#pragma once + +#include +#include + +namespace facebook { +namespace jni { + +class JThread : public JavaClass { + public: + static constexpr const char* kJavaDescriptor = "Ljava/lang/Thread;"; + + void start() { + static const auto method = javaClassStatic()->getMethod("start"); + method(self()); + } + + void join() { + static const auto method = javaClassStatic()->getMethod("join"); + method(self()); + } + + static local_ref create(std::function&& runnable) { + auto jrunnable = JNativeRunnable::newObjectCxxArgs(std::move(runnable)); + return newInstance(static_ref_cast(jrunnable)); + } + + static local_ref create(std::function&& runnable, std::string&& name) { + auto jrunnable = JNativeRunnable::newObjectCxxArgs(std::move(runnable)); + return newInstance(static_ref_cast(jrunnable), make_jstring(std::move(name))); + } + + static local_ref getCurrent() { + static const auto method = javaClassStatic()->getStaticMethod()>("currentThread"); + return method(javaClassStatic()); + } + + int getPriority() { + static const auto method = getClass()->getMethod("getPriority"); + return method(self()); + } + + void setPriority(int priority) { + static const auto method = getClass()->getMethod("setPriority"); + method(self(), priority); + } +}; + +} +} diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/NativeRunnable.h b/libs/fbjni/cxx/fbjni/NativeRunnable.h similarity index 52% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/NativeRunnable.h rename to libs/fbjni/cxx/fbjni/NativeRunnable.h index 0502e36b5..d2f911c95 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/NativeRunnable.h +++ b/libs/fbjni/cxx/fbjni/NativeRunnable.h @@ -1,15 +1,22 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ #pragma once -#include "CoreClasses.h" -#include "Hybrid.h" -#include "Registration.h" +#include #include diff --git a/libs/fbjni/cxx/fbjni/OnLoad.cpp b/libs/fbjni/cxx/fbjni/OnLoad.cpp new file mode 100644 index 000000000..2282131ef --- /dev/null +++ b/libs/fbjni/cxx/fbjni/OnLoad.cpp @@ -0,0 +1,28 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +#include +#include + +using namespace facebook::jni; + +JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { + return facebook::jni::initialize(vm, [] { + HybridDataOnLoad(); + JNativeRunnable::OnLoad(); + ThreadScope::OnLoad(); + }); +} diff --git a/libs/fbjni/cxx/fbjni/ReadableByteChannel.cpp b/libs/fbjni/cxx/fbjni/ReadableByteChannel.cpp new file mode 100644 index 000000000..9970d2842 --- /dev/null +++ b/libs/fbjni/cxx/fbjni/ReadableByteChannel.cpp @@ -0,0 +1,31 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +#include + +namespace facebook { +namespace jni { + +int JReadableByteChannel::read(alias_ref dest) const { + if (!self()) { + throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException"); + } + static auto method = javaClassStatic()->getMethod)>("read"); + return method(self(), dest); +} + +}} + diff --git a/libs/fbjni/cxx/fbjni/ReadableByteChannel.h b/libs/fbjni/cxx/fbjni/ReadableByteChannel.h new file mode 100644 index 000000000..cded4a603 --- /dev/null +++ b/libs/fbjni/cxx/fbjni/ReadableByteChannel.h @@ -0,0 +1,32 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +#pragma once + +#include +#include + +namespace facebook { +namespace jni { + +class JReadableByteChannel : public JavaClass { +public: + static constexpr const char* kJavaDescriptor = "Ljava/nio/channels/ReadableByteChannel;"; + + int read(alias_ref dest) const; +}; + +}} diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/Boxed.h b/libs/fbjni/cxx/fbjni/detail/Boxed.h similarity index 67% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/Boxed.h rename to libs/fbjni/cxx/fbjni/detail/Boxed.h index b47996163..3628639bd 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/Boxed.h +++ b/libs/fbjni/cxx/fbjni/detail/Boxed.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ #pragma once @@ -18,13 +27,13 @@ struct JPrimitive : JavaClass { using typename JavaClass::javaobject; using JavaClass::javaClassStatic; static local_ref valueOf(jprim val) { - static auto cls = javaClassStatic(); - static auto method = + static const auto cls = javaClassStatic(); + static const auto method = cls->template getStaticMethod("valueOf"); return method(cls, val); } jprim value() const { - static auto method = + static const auto method = javaClassStatic()->template getMethod(T::kValueMethod); return method(this->self()); } @@ -56,9 +65,12 @@ DEFINE_BOXED_PRIMITIVE(double, Double) #undef DEFINE_BOXED_PRIMITIVE +struct JVoid : public jni::JavaClass { + static auto constexpr kJavaDescriptor = "Ljava/lang/Void;"; +}; + inline local_ref autobox(alias_ref val) { return make_local(val); } }} - diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/Common.h b/libs/fbjni/cxx/fbjni/detail/Common.h similarity index 70% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/Common.h rename to libs/fbjni/cxx/fbjni/detail/Common.h index a7775db6d..b207cee84 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/Common.h +++ b/libs/fbjni/cxx/fbjni/detail/Common.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ /** @file Common.h @@ -16,9 +25,6 @@ #include -#include -#include - #ifdef FBJNI_DEBUG_REFS # ifdef __ANDROID__ # include @@ -43,11 +49,11 @@ namespace facebook { namespace jni { -FBEXPORT void throwPendingJniExceptionAsCppException(); -FBEXPORT void throwCppExceptionIf(bool condition); +void throwPendingJniExceptionAsCppException(); +void throwCppExceptionIf(bool condition); -[[noreturn]] FBEXPORT void throwNewJavaException(jthrowable); -[[noreturn]] FBEXPORT void throwNewJavaException(const char* throwableName, const char* msg); +[[noreturn]] void throwNewJavaException(jthrowable); +[[noreturn]] void throwNewJavaException(const char* throwableName, const char* msg); template [[noreturn]] void throwNewJavaException(const char* throwableName, const char* fmt, Args... args); @@ -66,20 +72,10 @@ template * unhelpful way (typically a segfault) while trying to handle an exception * which occurs later. */ -FBEXPORT jint initialize(JavaVM*, std::function&&) noexcept; +jint initialize(JavaVM*, std::function&&) noexcept; namespace internal { -/** - * Retrieve a pointer the JNI environment of the current thread. - * - * @pre The current thread must be attached to the VM - */ -inline JNIEnv* getEnv() noexcept { - // TODO(T6594868) Benchmark against raw JNI access - return Environment::current(); -} - // Define to get extremely verbose logging of references and to enable reference stats #ifdef FBJNI_DEBUG_REFS template diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/CoreClasses-inl.h b/libs/fbjni/cxx/fbjni/detail/CoreClasses-inl.h similarity index 85% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/CoreClasses-inl.h rename to libs/fbjni/cxx/fbjni/detail/CoreClasses-inl.h index 5258a240b..6d6db77e6 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/CoreClasses-inl.h +++ b/libs/fbjni/cxx/fbjni/detail/CoreClasses-inl.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ #pragma once @@ -22,15 +31,15 @@ namespace jni { // jobject ///////////////////////////////////////////////////////////////////////////////////////// inline bool isSameObject(alias_ref lhs, alias_ref rhs) noexcept { - return internal::getEnv()->IsSameObject(lhs.get(), rhs.get()) != JNI_FALSE; + return Environment::current()->IsSameObject(lhs.get(), rhs.get()) != JNI_FALSE; } inline local_ref JObject::getClass() const noexcept { - return adopt_local(internal::getEnv()->GetObjectClass(self())); + return adopt_local(Environment::current()->GetObjectClass(self())); } inline bool JObject::isInstanceOf(alias_ref cls) const noexcept { - return internal::getEnv()->IsInstanceOf(self(), cls.get()) != JNI_FALSE; + return Environment::current()->IsInstanceOf(self(), cls.get()) != JNI_FALSE; } template @@ -49,7 +58,7 @@ inline void JObject::setFieldValue(JField field, T value) noexcept { } inline std::string JObject::toString() const { - static auto method = findClassLocal("java/lang/Object")->getMethod("toString"); + static const auto method = findClassLocal("java/lang/Object")->getMethod("toString"); return method(self())->toStdString(); } @@ -78,13 +87,13 @@ MonitorLock::MonitorLock() noexcept : owned_(nullptr) {} MonitorLock::MonitorLock(alias_ref object) noexcept : owned_(object) { - internal::getEnv()->MonitorEnter(object.get()); + Environment::current()->MonitorEnter(object.get()); } void MonitorLock::reset() noexcept { if (owned_) { - internal::getEnv()->MonitorExit(owned_.get()); - if (internal::getEnv()->ExceptionCheck()) { + Environment::current()->MonitorExit(owned_.get()); + if (Environment::current()->ExceptionCheck()) { abort(); // Lock mismatch } owned_ = nullptr; @@ -127,7 +136,7 @@ namespace detail { template static local_ref newInstance(Args... args) { static auto cls = JC::javaClassStatic(); - static auto constructor = cls->template getConstructor(); + static const auto constructor = cls->template getConstructor(); return cls->newObject(constructor, args...); } } @@ -155,17 +164,18 @@ struct NativeMethod { }; inline local_ref JClass::getSuperclass() const noexcept { - return adopt_local(internal::getEnv()->GetSuperclass(self())); + return adopt_local(Environment::current()->GetSuperclass(self())); } inline void JClass::registerNatives(std::initializer_list methods) { - const auto env = internal::getEnv(); + const auto env = Environment::current(); JNINativeMethod jnimethods[methods.size()]; size_t i = 0; for (auto it = methods.begin(); it < methods.end(); ++it, ++i) { - jnimethods[i].name = it->name; - jnimethods[i].signature = it->descriptor.c_str(); + // The JNI struct members are unnecessarily non-const. + jnimethods[i].name = const_cast(it->name); + jnimethods[i].signature = const_cast(it->descriptor.c_str()); jnimethods[i].fnPtr = reinterpret_cast(it->wrapper); } @@ -174,8 +184,13 @@ inline void JClass::registerNatives(std::initializer_list methods) } inline bool JClass::isAssignableFrom(alias_ref other) const noexcept { - const auto env = internal::getEnv(); - const auto result = env->IsAssignableFrom(self(), other.get()); + const auto env = Environment::current(); + // Ths method has behavior compatible with the + // java.lang.Class#isAssignableFrom method. The order of the + // arguments to the JNI IsAssignableFrom C function is "opposite" + // from what some might expect, which makes this code look a little + // odd, but it is correct. + const auto result = env->IsAssignableFrom(other.get(), self()); return result; } @@ -199,7 +214,7 @@ template inline JMethod JClass::getMethod( const char* name, const char* descriptor) const { - const auto env = internal::getEnv(); + const auto env = Environment::current(); const auto method = env->GetMethodID(self(), name, descriptor); FACEBOOK_JNI_THROW_EXCEPTION_IF(!method); return JMethod{method}; @@ -214,7 +229,7 @@ template inline JStaticMethod JClass::getStaticMethod( const char* name, const char* descriptor) const { - const auto env = internal::getEnv(); + const auto env = Environment::current(); const auto method = env->GetStaticMethodID(self(), name, descriptor); FACEBOOK_JNI_THROW_EXCEPTION_IF(!method); return JStaticMethod{method}; @@ -229,7 +244,7 @@ template inline JNonvirtualMethod JClass::getNonvirtualMethod( const char* name, const char* descriptor) const { - const auto env = internal::getEnv(); + const auto env = Environment::current(); const auto method = env->GetMethodID(self(), name, descriptor); FACEBOOK_JNI_THROW_EXCEPTION_IF(!method); return JNonvirtualMethod{method}; @@ -245,7 +260,7 @@ template inline JField(), T>> JClass::getField( const char* name, const char* descriptor) const { - const auto env = internal::getEnv(); + const auto env = Environment::current(); auto field = env->GetFieldID(self(), name, descriptor); FACEBOOK_JNI_THROW_EXCEPTION_IF(!field); return JField{field}; @@ -261,7 +276,7 @@ template inline JStaticField(), T>> JClass::getStaticField( const char* name, const char* descriptor) const { - const auto env = internal::getEnv(); + const auto env = Environment::current(); auto field = env->GetStaticFieldID(self(), name, descriptor); FACEBOOK_JNI_THROW_EXCEPTION_IF(!field); return JStaticField{field}; @@ -286,7 +301,7 @@ template inline local_ref JClass::newObject( JConstructor constructor, Args... args) const { - const auto env = internal::getEnv(); + const auto env = Environment::current(); auto object = env->NewObject(self(), constructor.getId(), detail::callToJni( detail::Convert::type>::toCall(args))...); @@ -339,46 +354,11 @@ struct Convert { }; } -// JStackTrace ////////////////////////////////////////////////////////////////////////////////////// - -inline auto JStackTraceElement::create( - const std::string& declaringClass, const std::string& methodName, const std::string& file, int line) - -> local_ref { - return newInstance(declaringClass, methodName, file, line); -} - -inline std::string JStackTraceElement::getClassName() const { - static auto meth = javaClassStatic()->getMethod()>("getClassName"); - return meth(self())->toStdString(); -} - -inline std::string JStackTraceElement::getMethodName() const { - static auto meth = javaClassStatic()->getMethod()>("getMethodName"); - return meth(self())->toStdString(); -} - -inline std::string JStackTraceElement::getFileName() const { - static auto meth = javaClassStatic()->getMethod()>("getFileName"); - return meth(self())->toStdString(); -} - -inline int JStackTraceElement::getLineNumber() const { - static auto meth = javaClassStatic()->getMethod("getLineNumber"); - return meth(self()); -} - -// jthrowable ////////////////////////////////////////////////////////////////////////////////////// - -inline local_ref JThrowable::initCause(alias_ref cause) { - static auto meth = javaClassStatic()->getMethod("initCause"); - return meth(self(), cause.get()); -} - // jtypeArray ////////////////////////////////////////////////////////////////////////////////////// namespace detail { inline size_t JArray::size() const noexcept { - const auto env = internal::getEnv(); + const auto env = Environment::current(); return env->GetArrayLength(self()); } } @@ -438,8 +418,8 @@ std::string JArrayClass::get_instantiated_base_name() { template auto JArrayClass::newArray(size_t size) -> local_ref { - static auto elementClass = findClassStatic(jtype_traits::base_name().c_str()); - const auto env = internal::getEnv(); + static const auto elementClass = findClassStatic(jtype_traits::base_name().c_str()); + const auto env = Environment::current(); auto rawArray = env->NewObjectArray(size, elementClass.get(), nullptr); FACEBOOK_JNI_THROW_EXCEPTION_IF(!rawArray); return adopt_local(static_cast(rawArray)); @@ -447,13 +427,13 @@ auto JArrayClass::newArray(size_t size) -> local_ref { template inline void JArrayClass::setElement(size_t idx, const T& value) { - const auto env = internal::getEnv(); + const auto env = Environment::current(); env->SetObjectArrayElement(this->self(), idx, value); } template inline local_ref JArrayClass::getElement(size_t idx) { - const auto env = internal::getEnv(); + const auto env = Environment::current(); auto rawElement = env->GetObjectArrayElement(this->self(), idx); return adopt_local(static_cast(rawElement)); } @@ -463,6 +443,11 @@ inline detail::ElementProxy> JArrayClass::operator[](size_t in return detail::ElementProxy>(this, index); } +template +local_ref::javaobject> adopt_local_array(jobjectArray ref) { + return adopt_local(static_cast::javaobject>(ref)); +} + // jarray ///////////////////////////////////////////////////////////////////////////////////////// template @@ -537,7 +522,7 @@ class PinnedCriticalAlloc { T** elements, size_t* size, jboolean* isCopy) { - const auto env = internal::getEnv(); + const auto env = Environment::current(); *elements = static_cast(env->GetPrimitiveArrayCritical(array.get(), isCopy)); FACEBOOK_JNI_THROW_EXCEPTION_IF(!elements); *size = array->size(); @@ -548,7 +533,7 @@ class PinnedCriticalAlloc { jint start, jint size, jint mode) { - const auto env = internal::getEnv(); + const auto env = Environment::current(); env->ReleasePrimitiveArrayCritical(array.get(), elements, mode); } }; diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/CoreClasses.h b/libs/fbjni/cxx/fbjni/detail/CoreClasses.h similarity index 90% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/CoreClasses.h rename to libs/fbjni/cxx/fbjni/detail/CoreClasses.h index baa2768e9..47c551a51 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/CoreClasses.h +++ b/libs/fbjni/cxx/fbjni/detail/CoreClasses.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ #pragma once @@ -16,14 +25,11 @@ #include "References-forward.h" #include "Meta-forward.h" #include "TypeTraits.h" -#include #include #include -#include - namespace facebook { namespace jni { @@ -39,7 +45,7 @@ class JObject; /// in a "static auto" variable, or a static global. /// /// @return Returns a leaked global reference to the class -FBEXPORT alias_ref findClassStatic(const char* name); +alias_ref findClassStatic(const char* name); /// Lookup a class by name. Note this functions returns a local reference, /// which means that it must not be stored in a static variable. @@ -48,12 +54,12 @@ FBEXPORT alias_ref findClassStatic(const char* name); /// (like caching method ids). /// /// @return Returns a global reference to the class -FBEXPORT local_ref findClassLocal(const char* name); +local_ref findClassLocal(const char* name); /// Check to see if two references refer to the same object. Comparison with nullptr /// returns true if and only if compared to another nullptr. A weak reference that /// refers to a reclaimed object count as nullptr. -FBEXPORT bool isSameObject(alias_ref lhs, alias_ref rhs) noexcept; +bool isSameObject(alias_ref lhs, alias_ref rhs) noexcept; // Together, these classes allow convenient use of any class with the fbjni // helpers. To use: @@ -72,7 +78,7 @@ FBEXPORT bool isSameObject(alias_ref lhs, alias_ref rhs) noexc // constexpr static auto kJavaDescriptor = "Lcom/example/package/MyClass;"; // // void foo() { -// static auto method = javaClassStatic()->getMethod("foo"); +// static const auto method = javaClassStatic()->getMethod("foo"); // method(self()); // } // @@ -96,7 +102,7 @@ static local_ref newInstance(Args... args); class MonitorLock; -class FBEXPORT JObject : detail::JObjectBase { +class JObject : detail::JObjectBase { public: static constexpr auto kJavaDescriptor = "Ljava/lang/Object;"; @@ -192,7 +198,7 @@ struct JTypeFor { // jthrowable) to be used as javaobject. This should only be necessary for // built-in jni types and not user-defined ones. template -class FBEXPORT JavaClass : public Base { +class JavaClass : public Base { using JObjType = typename detail::JTypeFor; public: using _javaobject = typename JObjType::_javaobject; @@ -220,7 +226,7 @@ protected: /// Wrapper to provide functionality to jclass references struct NativeMethod; -class FBEXPORT JClass : public JavaClass { +class JClass : public JavaClass { public: /// Java type descriptor static constexpr const char* kJavaDescriptor = "Ljava/lang/Class;"; @@ -325,19 +331,23 @@ private: void registerNatives(const char* name, std::initializer_list methods); /// Wrapper to provide functionality to jstring references -class FBEXPORT JString : public JavaClass { +class JString : public JavaClass { public: /// Java type descriptor static constexpr const char* kJavaDescriptor = "Ljava/lang/String;"; /// Convenience method to convert a jstring object to a std::string std::string toStdString() const; + + /// Convenience method to convert a jstring object to a std::u16string + std::u16string toU16String() const; }; -/// Convenience functions to convert a std::string or const char* into a @ref local_ref to a -/// jstring -FBEXPORT local_ref make_jstring(const char* modifiedUtf8); -FBEXPORT local_ref make_jstring(const std::string& modifiedUtf8); +/// Convenience functions to convert a const char*, std::string, or std::u16string +/// into a @ref local_ref to a jstring. +local_ref make_jstring(const char* modifiedUtf8); +local_ref make_jstring(const std::string& modifiedUtf8); +local_ref make_jstring(const std::u16string& utf16); namespace detail { template @@ -365,7 +375,7 @@ class ElementProxy { } namespace detail { -class FBEXPORT JArray : public JavaClass { +class JArray : public JavaClass { public: // This cannot be used in a scope that derives a descriptor (like in a method // signature). Use a more derived type instead (like JArrayInt or @@ -377,7 +387,7 @@ class FBEXPORT JArray : public JavaClass { // This is used so that the JArrayClass javaobject extends jni's // jobjectArray. This class should not be used directly. A general Object[] // should use JArrayClass. -class FBEXPORT JTypeArray : public JavaClass { +class JTypeArray : public JavaClass { // This cannot be used in a scope that derives a descriptor (like in a method // signature). static constexpr const char* kJavaDescriptor = nullptr; @@ -427,36 +437,13 @@ template using jtypeArray = typename JArrayClass::javaobject; template -local_ref::javaobject> adopt_local_array(jobjectArray ref) { - return adopt_local(static_cast::javaobject>(ref)); -} +local_ref::javaobject> adopt_local_array(jobjectArray ref); template local_ref adopt_local(detail::ElementProxy elementProxy) { return static_cast>(elementProxy); } - -struct FBEXPORT JStackTraceElement : JavaClass { - static auto constexpr kJavaDescriptor = "Ljava/lang/StackTraceElement;"; - - static local_ref create(const std::string& declaringClass, const std::string& methodName, const std::string& file, int line); - - std::string getClassName() const; - std::string getMethodName() const; - std::string getFileName() const; - int getLineNumber() const; -}; - -/// Wrapper to provide functionality to jthrowable references -class FBEXPORT JThrowable : public JavaClass { - public: - static constexpr const char* kJavaDescriptor = "Ljava/lang/Throwable;"; - local_ref initCause(alias_ref cause); - using JStackTrace = JArrayClass; - local_ref getStackTrace(); -}; - template class PinnedPrimitiveArray; @@ -468,7 +455,7 @@ template class PinnedCriticalAlloc; /// This is an empty holder by itself. Construct a PinnedPrimitiveArray to actually interact with /// the elements of the array. template -class FBEXPORT JPrimitiveArray : +class JPrimitiveArray : public JavaClass, detail::JArray, JArrayType> { static_assert(is_jni_primitive_array(), ""); public: @@ -508,14 +495,14 @@ private: void releaseElements(T* elements, jint mode); }; -FBEXPORT local_ref make_boolean_array(jsize size); -FBEXPORT local_ref make_byte_array(jsize size); -FBEXPORT local_ref make_char_array(jsize size); -FBEXPORT local_ref make_short_array(jsize size); -FBEXPORT local_ref make_int_array(jsize size); -FBEXPORT local_ref make_long_array(jsize size); -FBEXPORT local_ref make_float_array(jsize size); -FBEXPORT local_ref make_double_array(jsize size); +local_ref make_boolean_array(jsize size); +local_ref make_byte_array(jsize size); +local_ref make_char_array(jsize size); +local_ref make_short_array(jsize size); +local_ref make_int_array(jsize size); +local_ref make_long_array(jsize size); +local_ref make_float_array(jsize size); +local_ref make_double_array(jsize size); using JArrayBoolean = JPrimitiveArray; using JArrayByte = JPrimitiveArray; @@ -577,6 +564,29 @@ class PinnedPrimitiveArray { friend class JPrimitiveArray::array_type>; }; +struct JStackTraceElement : JavaClass { + static auto constexpr kJavaDescriptor = "Ljava/lang/StackTraceElement;"; + + static local_ref create(const std::string& declaringClass, const std::string& methodName, const std::string& file, int line); + + std::string getClassName() const; + std::string getMethodName() const; + std::string getFileName() const; + int getLineNumber() const; +}; + +/// Wrapper to provide functionality to jthrowable references +class JThrowable : public JavaClass { + public: + static constexpr const char* kJavaDescriptor = "Ljava/lang/Throwable;"; + + using JStackTrace = JArrayClass; + + local_ref initCause(alias_ref cause); + local_ref getStackTrace(); + void setStackTrace(alias_ref>); +}; + #pragma push_macro("PlainJniRefMap") #undef PlainJniRefMap #define PlainJniRefMap(rtype, jtype) \ diff --git a/libs/fbjni/cxx/fbjni/detail/Environment.cpp b/libs/fbjni/cxx/fbjni/detail/Environment.cpp new file mode 100644 index 000000000..4911076cc --- /dev/null +++ b/libs/fbjni/cxx/fbjni/detail/Environment.cpp @@ -0,0 +1,301 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +#include + +#include +#include + +namespace facebook { +namespace jni { + +namespace { + +JavaVM* g_vm = nullptr; + +struct EnvironmentInitializer { + EnvironmentInitializer(JavaVM* vm) { + FBJNI_ASSERT(!g_vm); + FBJNI_ASSERT(vm); + g_vm = vm; + } +}; + +int getEnv(JNIEnv** env) { + FBJNI_ASSERT(g_vm); + // g_vm->GetEnv() might not clear the env* in failure cases. + *env = nullptr; + jint ret = g_vm->GetEnv((void**)env, JNI_VERSION_1_6); + // Other possibilites are that JNI_VERSION_1_6 is invalid, or some + // unknown return was received. + FBJNI_ASSERT(ret == JNI_OK || ret == JNI_EDETACHED); + return ret; +} + +// Some jni.h define the first arg to AttachCurrentThread as void**, +// and some as JNIEnv**. This hack allows both to work. + +template +struct AttachTraits; + +template <> +struct AttachTraits { + using EnvType = JNIEnv*; +}; + +template <> +struct AttachTraits { + using EnvType = void*; +}; + +JNIEnv* attachCurrentThread() { + JavaVMAttachArgs args{JNI_VERSION_1_6, nullptr, nullptr}; + using AttachEnvType = + typename AttachTraits::EnvType; + AttachEnvType env; + auto result = g_vm->AttachCurrentThread(&env, &args); + FBJNI_ASSERT(result == JNI_OK); + return reinterpret_cast(env); +} + +} + +/* static */ +void Environment::initialize(JavaVM* vm) { + static EnvironmentInitializer init(vm); +} + +namespace { + +pthread_key_t makeKey() { + pthread_key_t key; + int ret = pthread_key_create(&key, nullptr); + if (ret != 0) { + FBJNI_LOGF("pthread_key_create failed: %d", ret); + } + return key; +} + +pthread_key_t getTLKey() { + static pthread_key_t key = makeKey(); + return key; +} + +inline detail::TLData* getTLData(pthread_key_t key) { + return reinterpret_cast(pthread_getspecific(key)); +} + +inline void setTLData(pthread_key_t key, detail::TLData* data) { + int ret = pthread_setspecific(key, data); + if (ret != 0) { + (void) ret; + FBJNI_LOGF("pthread_setspecific failed: %d", ret); + } +} + +// This returns non-nullptr iff the env was cached from java. So it +// can return nullptr for a thread which has been registered. +inline JNIEnv* cachedOrNull() { + detail::TLData* pdata = getTLData(getTLKey()); + return (pdata ? pdata->env : nullptr); +} + +} + +namespace detail { + +// This will return a cached env if there is one, or get one from JNI +// if the thread has already been attached some other way. If it +// returns nullptr, then the thread has never been registered, or the +// VM has never been set up for fbjni. + +JNIEnv* currentOrNull() { + if (!g_vm) { + return nullptr; + } + + detail::TLData* pdata = getTLData(getTLKey()); + if (pdata && pdata->env) { + return pdata->env; + } + + JNIEnv* env; + if (getEnv(&env) != JNI_OK) { + // If there's a ThreadScope on the stack, we should have gotten a + // JNIEnv and not ended up here. + FBJNI_ASSERT(!pdata || !pdata->attached); + } + return env; +} + +// To understand JniEnvCacher and ThreadScope, it is helpful to +// realize that if a flagged JniEnvCacher is on the stack, then a +// flagged ThreadScope cannot be after it. If a flagged ThreadCacher +// is on the stack, then a JniEnvCacher *can* be after it. So, +// ThreadScope's setup and teardown can both assume they are the +// first/last interesting objects, but this is not true of +// JniEnvCacher. + +JniEnvCacher::JniEnvCacher(JNIEnv* env) + : thisCached_(false) +{ + FBJNI_ASSERT(env); + + pthread_key_t key = getTLKey(); + detail::TLData* pdata = getTLData(key); + if (pdata && pdata->env) { + return; + } + + if (!pdata) { + pdata = &data_; + setTLData(key, pdata); + pdata->attached = false; + } else { + FBJNI_ASSERT(!pdata->env); + } + + pdata->env = env; + + thisCached_ = true; +} + +JniEnvCacher::~JniEnvCacher() { + if (!thisCached_) { + return; + } + + pthread_key_t key = getTLKey(); + TLData* pdata = getTLData(key); + FBJNI_ASSERT(pdata); + FBJNI_ASSERT(pdata->env != nullptr); + pdata->env = nullptr; + if (!pdata->attached) { + setTLData(key, nullptr); + } +} + +} + +ThreadScope::ThreadScope() + : thisAttached_(false) +{ + if (g_vm == nullptr) { + throw std::runtime_error("fbjni is uninitialized; no thread can be attached."); + } + + JNIEnv* env; + + // Check if the thread is attached somehow. + auto result = getEnv(&env); + if (result == JNI_OK) { + return; + } + + // At this point, it appears there's no thread attached and no env is + // cached, or we would have returned already. So there better not + // be TLData. + + pthread_key_t key = getTLKey(); + detail::TLData* pdata = getTLData(key); + FBJNI_ASSERT(pdata == nullptr); + setTLData(key, &data_); + + attachCurrentThread(); + + data_.env = nullptr; + data_.attached = true; + + thisAttached_ = true; +} + +ThreadScope::~ThreadScope() { + if (!thisAttached_) { + return; + } + + pthread_key_t key = getTLKey(); + detail::TLData* pdata = getTLData(key); + FBJNI_ASSERT(pdata); + FBJNI_ASSERT(pdata->env == nullptr); + FBJNI_ASSERT(pdata->attached); + FBJNI_ASSERT(g_vm); + g_vm->DetachCurrentThread(); + setTLData(key, nullptr); +} + +/* static */ +JNIEnv* Environment::current() { + FBJNI_ASSERT(g_vm); + JNIEnv* env = detail::currentOrNull(); + if (env == nullptr) { + throw std::runtime_error("Unable to retrieve jni environment. Is the thread attached?"); + } + return env; +} + +/* static */ +JNIEnv* Environment::ensureCurrentThreadIsAttached() { + FBJNI_ASSERT(g_vm); + JNIEnv* env = detail::currentOrNull(); + if (env == nullptr) { + env = attachCurrentThread(); + FBJNI_ASSERT(env); + } + return env; +} + +namespace { +struct JThreadScopeSupport : JavaClass { + static auto constexpr kJavaDescriptor = "Lcom/facebook/jni/ThreadScopeSupport;"; + + // These reinterpret_casts are a totally dangerous pattern. Don't use them. Use HybridData instead. + static void runStdFunction(std::function&& func) { + static const auto method = javaClassStatic()->getStaticMethod("runStdFunction"); + method(javaClassStatic(), reinterpret_cast(&func)); + } + + static void runStdFunctionImpl(alias_ref, jlong ptr) { + (*reinterpret_cast*>(ptr))(); + } + + static void OnLoad() { + // We need the javaClassStatic so that the class lookup is cached and that + // runStdFunction can be called from a ThreadScope-attached thread. + javaClassStatic()->registerNatives({ + makeNativeMethod("runStdFunctionImpl", runStdFunctionImpl), + }); + } +}; +} + +/* static */ +void ThreadScope::OnLoad() { + // These classes are required for ScopeWithClassLoader. Ensure they are looked up when loading. + JThreadScopeSupport::OnLoad(); +} + +/* static */ +void ThreadScope::WithClassLoader(std::function&& runnable) { + if (cachedOrNull() == nullptr) { + ThreadScope ts; + JThreadScopeSupport::runStdFunction(std::move(runnable)); + } else { + runnable(); + } +} + +} } diff --git a/libs/fbjni/src/main/cpp/include/fb/Environment.h b/libs/fbjni/cxx/fbjni/detail/Environment.h similarity index 50% rename from libs/fbjni/src/main/cpp/include/fb/Environment.h rename to libs/fbjni/cxx/fbjni/detail/Environment.h index e63db9cb2..e48fcbe89 100644 --- a/libs/fbjni/src/main/cpp/include/fb/Environment.h +++ b/libs/fbjni/cxx/fbjni/detail/Environment.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ #pragma once @@ -10,24 +19,69 @@ #include #include -#include namespace facebook { namespace jni { // Keeps a thread-local reference to the current thread's JNIEnv. struct Environment { - // May be null if this thread isn't attached to the JVM - FBEXPORT static JNIEnv* current(); + // Throws a std::runtime_error if this thread isn't attached to the JVM + // TODO(T6594868) Benchmark against raw JNI access + static JNIEnv* current(); static void initialize(JavaVM* vm); // There are subtle issues with calling the next functions directly. It is // much better to always use a ThreadScope to manage attaching/detaching for // you. - FBEXPORT static JNIEnv* ensureCurrentThreadIsAttached(); - FBEXPORT static void detachCurrentThread(); + static JNIEnv* ensureCurrentThreadIsAttached(); }; +namespace detail { + +// This will return null the thread isn't attached to the VM, or if +// fbjni has never been initialized with a VM at all. You probably +// shouldn't be using this. +JNIEnv* currentOrNull(); + +/** + * If there's thread-local data, it's a pointer to one of these. The + * instance is a member of JniEnvCacher or ThreadScope, and lives on + * the stack. + */ +struct TLData { + // This is modified only by JniEnvCacher, and is guaranteed to be + // valid if set, and refer to an env which originated from a JNI + // call into C++. + JNIEnv* env; + // This is modified only by ThreadScope, and is set only if an + // instance of ThreadScope which attached is on the stack. + bool attached; +}; + +/** + * RAII object which manages a cached JNIEnv* value. A Value is only + * cached if it is guaranteed safe, which means when C++ is called + * from a registered fbjni function. + */ +class JniEnvCacher { +public: + JniEnvCacher(JNIEnv* env); + JniEnvCacher(JniEnvCacher&) = delete; + JniEnvCacher(JniEnvCacher&&) = default; + JniEnvCacher& operator=(JniEnvCacher&) = delete; + JniEnvCacher& operator=(JniEnvCacher&&) = delete; + ~JniEnvCacher(); + +private: + // If this flag is set, then, this object needs to clear the cache. + bool thisCached_; + + // The thread local pointer may point here. + detail::TLData data_; +}; + +} + /** * RAII Object that attaches a thread to the JVM. Failing to detach from a thread before it * exits will cause a crash, as will calling Detach an extra time, and this guard class helps @@ -49,8 +103,11 @@ struct Environment { * class or instance to the new thread; this bypasses the need for the class loader. * (See http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html#attach_current_thread) * If you need access to the application's classes, you can use ThreadScope::WithClassLoader. + * - If fbjni has never been initialized, there will be no JavaVM object to attach with. + * In that case, a std::runtime_error will be thrown. This is only likely to happen in a + * standalone C++ application, or if Environment::initialize is not used. */ -class FBEXPORT ThreadScope { +class ThreadScope { public: ThreadScope(); ThreadScope(ThreadScope&) = delete; @@ -68,8 +125,14 @@ class FBEXPORT ThreadScope { static void WithClassLoader(std::function&& runnable); static void OnLoad(); + private: - bool attachedWithThisScope_; + // If this flag is set, then this object needs to detach. + bool thisAttached_; + + // The thread local pointer may point here. + detail::TLData data_; }; + } } diff --git a/libs/fbjni/cxx/fbjni/detail/Exceptions.cpp b/libs/fbjni/cxx/fbjni/detail/Exceptions.cpp new file mode 100644 index 000000000..6291d54ad --- /dev/null +++ b/libs/fbjni/cxx/fbjni/detail/Exceptions.cpp @@ -0,0 +1,400 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +#include "CoreClasses.h" +#include "Log.h" + +#ifndef FBJNI_NO_EXCEPTION_PTR +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace facebook { +namespace jni { + +namespace { +class JRuntimeException : public JavaClass { + public: + static auto constexpr kJavaDescriptor = "Ljava/lang/RuntimeException;"; + + static local_ref create(const char* str) { + return newInstance(make_jstring(str)); + } + + static local_ref create() { + return newInstance(); + } +}; + +class JIOException : public JavaClass { + public: + static auto constexpr kJavaDescriptor = "Ljava/io/IOException;"; + + static local_ref create(const char* str) { + return newInstance(make_jstring(str)); + } +}; + +class JOutOfMemoryError : public JavaClass { + public: + static auto constexpr kJavaDescriptor = "Ljava/lang/OutOfMemoryError;"; + + static local_ref create(const char* str) { + return newInstance(make_jstring(str)); + } +}; + +class JArrayIndexOutOfBoundsException : public JavaClass { + public: + static auto constexpr kJavaDescriptor = "Ljava/lang/ArrayIndexOutOfBoundsException;"; + + static local_ref create(const char* str) { + return newInstance(make_jstring(str)); + } +}; + +class JUnknownCppException : public JavaClass { + public: + static auto constexpr kJavaDescriptor = "Lcom/facebook/jni/UnknownCppException;"; + + static local_ref create() { + return newInstance(); + } + + static local_ref create(const char* str) { + return newInstance(make_jstring(str)); + } +}; + +class JCppSystemErrorException : public JavaClass { + public: + static auto constexpr kJavaDescriptor = "Lcom/facebook/jni/CppSystemErrorException;"; + + static local_ref create(const std::system_error& e) { + return newInstance(make_jstring(e.what()), e.code().value()); + } +}; + +// Exception throwing & translating functions ////////////////////////////////////////////////////// + +// Functions that throw Java exceptions + +void setJavaExceptionAndAbortOnFailure(alias_ref throwable) { + auto env = Environment::current(); + if (throwable) { + env->Throw(throwable.get()); + } + if (env->ExceptionCheck() != JNI_TRUE) { + FBJNI_LOGF("Failed to set Java exception"); + } +} + +} + +// Functions that throw C++ exceptions + +// TODO(T6618159) Inject the c++ stack into the exception's stack trace. One +// issue: when a java exception is created, it captures the full java stack +// across jni boundaries. lyra will only capture the c++ stack to the jni +// boundary. So, as we pass the java exception up to c++, we need to capture +// the c++ stack and then insert it into the correct place in the java stack +// trace. Then, as the exception propagates across the boundaries, we will +// slowly fill in the c++ parts of the trace. +void throwPendingJniExceptionAsCppException() { + JNIEnv* env = Environment::current(); + if (env->ExceptionCheck() == JNI_FALSE) { + return; + } + + auto throwable = adopt_local(env->ExceptionOccurred()); + if (!throwable) { + throw std::runtime_error("Unable to get pending JNI exception."); + } + env->ExceptionClear(); + + throw JniException(throwable); +} + +void throwCppExceptionIf(bool condition) { + if (!condition) { + return; + } + + auto env = Environment::current(); + if (env->ExceptionCheck() == JNI_TRUE) { + throwPendingJniExceptionAsCppException(); + return; + } + + throw JniException(); +} + +void throwNewJavaException(jthrowable throwable) { + throw JniException(wrap_alias(throwable)); +} + +void throwNewJavaException(const char* throwableName, const char* msg) { + // If anything of the fbjni calls fail, an exception of a suitable + // form will be thrown, which is what we want. + auto throwableClass = findClassLocal(throwableName); + auto throwable = throwableClass->newObject( + throwableClass->getConstructor(), + make_jstring(msg).release()); + throwNewJavaException(throwable.get()); +} + +// jthrowable ////////////////////////////////////////////////////////////////////////////////////// + +local_ref JThrowable::initCause(alias_ref cause) { + static auto meth = javaClassStatic()->getMethod)>("initCause"); + return meth(self(), cause); +} + +auto JThrowable::getStackTrace() -> local_ref { + static auto meth = javaClassStatic()->getMethod("getStackTrace"); + return meth(self()); +} + +void JThrowable::setStackTrace(alias_ref stack) { + static auto meth = javaClassStatic()->getMethod)>("setStackTrace"); + return meth(self(), stack); +} + +auto JStackTraceElement::create( + const std::string& declaringClass, const std::string& methodName, const std::string& file, int line) + -> local_ref { + return newInstance(declaringClass, methodName, file, line); +} + +std::string JStackTraceElement::getClassName() const { + static auto meth = javaClassStatic()->getMethod()>("getClassName"); + return meth(self())->toStdString(); +} + +std::string JStackTraceElement::getMethodName() const { + static auto meth = javaClassStatic()->getMethod()>("getMethodName"); + return meth(self())->toStdString(); +} + +std::string JStackTraceElement::getFileName() const { + static auto meth = javaClassStatic()->getMethod()>("getFileName"); + return meth(self())->toStdString(); +} + +int JStackTraceElement::getLineNumber() const { + static auto meth = javaClassStatic()->getMethod("getLineNumber"); + return meth(self()); +} + +// Translate C++ to Java Exception + +namespace { + +// For each exception in the chain of the exception_ptr argument, func +// will be called with that exception (in reverse order, i.e. innermost first). +#ifndef FBJNI_NO_EXCEPTION_PTR +void denest(const std::function& func, std::exception_ptr ptr) { + FBJNI_ASSERT(ptr); + try { + std::rethrow_exception(ptr); + } catch (const std::nested_exception& e) { + denest(func, e.nested_ptr()); + } catch (...) { + // ignored. + } + func(ptr); + } +#endif + +} // namespace + +#ifndef FBJNI_NO_EXCEPTION_PTR +local_ref createJStackTraceElement(const lyra::StackTraceElement& cpp) { + return JStackTraceElement::create( + "|lyra|{" + cpp.libraryName() + "}", cpp.functionName(), cpp.buildId(), cpp.libraryOffset()); +} + +void addCppStacktraceToJavaException(alias_ref java, std::exception_ptr cpp) { + auto cppStack = lyra::getStackTraceSymbols( + (cpp == nullptr) ? + lyra::getStackTrace() + : lyra::getExceptionTrace(cpp)); + + auto javaStack = java->getStackTrace(); + auto newStack = JThrowable::JStackTrace::newArray(javaStack->size() + cppStack.size()); + size_t i = 0; + for (size_t j = 0; j < cppStack.size(); j++, i++) { + (*newStack)[i] = createJStackTraceElement(cppStack[j]); + } + for (size_t j = 0; j < javaStack->size(); j++, i++) { + (*newStack)[i] = (*javaStack)[j]; + } + java->setStackTrace(newStack); +} + +local_ref convertCppExceptionToJavaException(std::exception_ptr ptr) { + FBJNI_ASSERT(ptr); + local_ref current; + bool addCppStack = true; + try { + std::rethrow_exception(ptr); + addCppStack = false; + } catch (const JniException& ex) { + current = ex.getThrowable(); + } catch (const std::ios_base::failure& ex) { + current = JIOException::create(ex.what()); + } catch (const std::bad_alloc& ex) { + current = JOutOfMemoryError::create(ex.what()); + } catch (const std::out_of_range& ex) { + current = JArrayIndexOutOfBoundsException::create(ex.what()); + } catch (const std::system_error& ex) { + current = JCppSystemErrorException::create(ex); + } catch (const std::runtime_error& ex) { + current = JRuntimeException::create(ex.what()); + } catch (const std::exception& ex) { + current = JCppException::create(ex.what()); + } catch (const char* msg) { + current = JUnknownCppException::create(msg); + } catch (...) { + current = JUnknownCppException::create(); + } + + if (addCppStack) { + addCppStacktraceToJavaException(current, ptr); + } + return current; + } +#endif + +local_ref getJavaExceptionForCppBackTrace() { + return getJavaExceptionForCppBackTrace(nullptr); +} + +local_ref getJavaExceptionForCppBackTrace(const char* msg) { + local_ref current = + msg ? JUnknownCppException::create(msg) : JUnknownCppException::create(); +#ifndef FBJNI_NO_EXCEPTION_PTR + addCppStacktraceToJavaException(current, nullptr); +#endif + return current; +} + + +#ifndef FBJNI_NO_EXCEPTION_PTR +local_ref getJavaExceptionForCppException(std::exception_ptr ptr) { + FBJNI_ASSERT(ptr); + local_ref previous; + auto func = [&previous] (std::exception_ptr ptr) { + auto current = convertCppExceptionToJavaException(ptr); + if (previous) { + current->initCause(previous); + } + previous = current; + }; + denest(func, ptr); + return previous; +} +#endif + +void translatePendingCppExceptionToJavaException() { + try { +#ifndef FBJNI_NO_EXCEPTION_PTR + auto exc = getJavaExceptionForCppException(std::current_exception()); +#else + auto exc = JUnknownCppException::create(); +#endif + setJavaExceptionAndAbortOnFailure(exc); + } catch (...) { +#ifndef FBJNI_NO_EXCEPTION_PTR + FBJNI_LOGE( + "Unexpected error in translatePendingCppExceptionToJavaException(): %s", + lyra::toString(std::current_exception()).c_str()); +#else + FBJNI_LOGE( + "Unexpected error in translatePendingCppExceptionToJavaException()"); +#endif + std::terminate(); + } +} + +// JniException //////////////////////////////////////////////////////////////////////////////////// + +const std::string JniException::kExceptionMessageFailure_ = "Unable to get exception message."; + +JniException::JniException() : JniException(JRuntimeException::create()) { } + +JniException::JniException(alias_ref throwable) : isMessageExtracted_(false) { + throwable_ = make_global(throwable); +} + +JniException::JniException(JniException &&rhs) + : throwable_(std::move(rhs.throwable_)), + what_(std::move(rhs.what_)), + isMessageExtracted_(rhs.isMessageExtracted_) { +} + +JniException::JniException(const JniException &rhs) + : what_(rhs.what_), isMessageExtracted_(rhs.isMessageExtracted_) { + throwable_ = make_global(rhs.throwable_); +} + +JniException::~JniException() { + try { + ThreadScope ts; + throwable_.reset(); + } catch (...) { + FBJNI_LOGE("Exception in ~JniException()"); + std::terminate(); + } +} + +local_ref JniException::getThrowable() const noexcept { + return make_local(throwable_); +} + +// TODO 6900503: consider making this thread-safe. +void JniException::populateWhat() const noexcept { + try { + ThreadScope ts; + what_ = throwable_->toString(); + isMessageExtracted_ = true; + } catch(...) { + what_ = kExceptionMessageFailure_; + } +} + +const char* JniException::what() const noexcept { + if (!isMessageExtracted_) { + populateWhat(); + } + return what_.c_str(); +} + +void JniException::setJavaException() const noexcept { + setJavaExceptionAndAbortOnFailure(throwable_); +} + +}} diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/Exceptions.h b/libs/fbjni/cxx/fbjni/detail/Exceptions.h similarity index 70% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/Exceptions.h rename to libs/fbjni/cxx/fbjni/detail/Exceptions.h index 08deb42e8..2073beba1 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/Exceptions.h +++ b/libs/fbjni/cxx/fbjni/detail/Exceptions.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ /** @@ -24,12 +33,15 @@ #include -#include - #include "Common.h" #include "References.h" #include "CoreClasses.h" +#if defined(__ANDROID__) && defined(__ARM_ARCH_5TE__) && !defined(FBJNI_NO_EXCEPTION_PTR) +// ARMv5 NDK does not support exception_ptr so we cannot use that when building for it. +#define FBJNI_NO_EXCEPTION_PTR +#endif + namespace facebook { namespace jni { @@ -58,7 +70,7 @@ class JCppException : public JavaClass { * * Note: the what() method of this class is not thread-safe (t6900503). */ -class FBEXPORT JniException : public std::exception { +class JniException : public std::exception { public: JniException(); ~JniException(); @@ -106,11 +118,23 @@ template } // Identifies any pending C++ exception and throws it as a Java exception. If the exception can't -// be thrown, it aborts the program. This is a noexcept function at C++ level. -FBEXPORT void translatePendingCppExceptionToJavaException() noexcept; +// be thrown, it aborts the program. +void translatePendingCppExceptionToJavaException(); + +#ifndef FBJNI_NO_EXCEPTION_PTR +local_ref getJavaExceptionForCppException(std::exception_ptr ptr); +#endif + +/*** + * The stack returned may include build ids. It may be beneficial to + * call lyra::setLibraryIdentifierFunction before calling this if + * build ids are desirable. + */ +local_ref getJavaExceptionForCppBackTrace(); + +local_ref getJavaExceptionForCppBackTrace(const char* msg); // For convenience, some exception names in java.lang are available here. - const char* const gJavaLangIllegalArgumentException = "java/lang/IllegalArgumentException"; }} diff --git a/libs/fbjni/cxx/fbjni/detail/Hybrid.cpp b/libs/fbjni/cxx/fbjni/detail/Hybrid.cpp new file mode 100644 index 000000000..3ba4f4d0e --- /dev/null +++ b/libs/fbjni/cxx/fbjni/detail/Hybrid.cpp @@ -0,0 +1,42 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +#include + +namespace facebook { +namespace jni { + +namespace detail { + +local_ref HybridData::create() { + return newInstance(); +} + +} + +namespace { +void deleteNative(alias_ref, jlong ptr) { + delete reinterpret_cast(ptr); +} +} + +void HybridDataOnLoad() { + registerNatives("com/facebook/jni/HybridData$Destructor", { + makeNativeMethod("deleteNative", deleteNative), + }); +} + +}} diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/Hybrid.h b/libs/fbjni/cxx/fbjni/detail/Hybrid.h similarity index 67% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/Hybrid.h rename to libs/fbjni/cxx/fbjni/detail/Hybrid.h index f020826cb..d84dd31e1 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/Hybrid.h +++ b/libs/fbjni/cxx/fbjni/detail/Hybrid.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ #pragma once @@ -10,9 +19,6 @@ #include #include -#include -#include - #include "CoreClasses.h" namespace facebook { @@ -25,13 +31,45 @@ public: virtual ~BaseHybridClass() {} }; -struct FBEXPORT HybridData : public JavaClass { +struct HybridData : public JavaClass { constexpr static auto kJavaDescriptor = "Lcom/facebook/jni/HybridData;"; - void setNativePointer(std::unique_ptr new_value); - BaseHybridClass* getNativePointer(); static local_ref create(); }; +class HybridDestructor : public JavaClass { + public: + static auto constexpr kJavaDescriptor = "Lcom/facebook/jni/HybridData$Destructor;"; + + detail::BaseHybridClass* getNativePointer(); + + void setNativePointer(std::unique_ptr new_value); +}; + +template +detail::BaseHybridClass* getNativePointer(T t) { + return getHolder(t)->getNativePointer(); +} + +template +void setNativePointer(T t, std::unique_ptr new_value) { + getHolder(t)->setNativePointer(std::move(new_value)); +} + +template +local_ref getHolder(T t) { + static auto holderField = t->getClass()->template getField("mDestructor"); + return t->getFieldValue(holderField); +} + +// JavaClass for HybridClassBase +struct HybridClassBase : public JavaClass { + constexpr static auto kJavaDescriptor = "Lcom/facebook/jni/HybridClassBase;"; + + static bool isHybridClassBase(alias_ref jclass) { + return HybridClassBase::javaClassStatic()->isAssignableFrom(jclass); + } +}; + template struct HybridTraits { // This static assert should actually always fail if we don't use one of the @@ -66,7 +104,7 @@ struct HybridTraits< // convert to HybridClass* from jhybridobject template -struct FBEXPORT Convert< +struct Convert< T, typename std::enable_if< std::is_base_of::type>::value>::type> { typedef typename std::remove_pointer::type::jhybridobject jniType; @@ -91,7 +129,7 @@ struct RefReprType -class FBEXPORT HybridClass : public detail::HybridTraits::CxxBase { +class HybridClass : public detail::HybridTraits::CxxBase { public: struct JavaPart : JavaClass::JavaBase> { // At this point, T is incomplete, and so we cannot access @@ -108,6 +146,7 @@ public: T* cthis(); friend class HybridClass; + friend T; }; using jhybridobject = typename JavaPart::javaobject; @@ -137,7 +176,7 @@ protected: static local_ref makeHybridData(std::unique_ptr cxxPart) { auto hybridData = detail::HybridData::create(); - hybridData->setNativePointer(std::move(cxxPart)); + setNativePointer(hybridData, std::move(cxxPart)); return hybridData; } @@ -146,6 +185,11 @@ protected: return makeHybridData(std::unique_ptr(new T(std::forward(args)...))); } + template + static void setCxxInstance(alias_ref o, Args&&... args) { + setNativePointer(o, std::unique_ptr(new T(std::forward(args)...))); + } + public: // Factory method for creating a hybrid object where the arguments // are used to initialize the C++ part directly without passing them @@ -159,11 +203,23 @@ public: // C++ object fails, or any JNI methods throw. template static local_ref newObjectCxxArgs(Args&&... args) { - auto hybridData = makeCxxInstance(std::forward(args)...); - return JavaPart::newInstance(hybridData); + static bool isHybrid = detail::HybridClassBase::isHybridClassBase(javaClassStatic()); + auto cxxPart = std::unique_ptr(new T(std::forward(args)...)); + + local_ref result; + if (isHybrid) { + result = JavaPart::newInstance(); + setNativePointer(result, std::move(cxxPart)); + } + else { + auto hybridData = makeHybridData(std::move(cxxPart)); + result = JavaPart::newInstance(hybridData); + } + + return result; } - // TODO? Create reusable interface for Allocatable classes and use it to + // TODO? Create reusable interface for Allocatable classes and use it to // strengthen type-checking (and possibly provide a default // implementation of allocate().) template @@ -193,17 +249,23 @@ public: template inline T* HybridClass::JavaPart::cthis() { - static auto field = - HybridClass::JavaPart::javaClassStatic()->template getField("mHybridData"); - auto hybridData = this->getFieldValue(field); - if (!hybridData) { - throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException"); + detail::BaseHybridClass* result = 0; + static bool isHybrid = detail::HybridClassBase::isHybridClassBase(this->getClass()); + if (isHybrid) { + result = getNativePointer(this); + } else { + static auto field = + HybridClass::JavaPart::javaClassStatic()->template getField("mHybridData"); + auto hybridData = this->getFieldValue(field); + if (!hybridData) { + throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException"); + } + + result = getNativePointer(hybridData); } + // I'd like to use dynamic_cast here, but -fno-rtti is the default. - T* value = static_cast(hybridData->getNativePointer()); - // This would require some serious programmer error. - FBASSERTMSGF(value != 0, "Incorrect C++ type in hybrid field"); - return value; + return static_cast(result); }; template diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/Iterator-inl.h b/libs/fbjni/cxx/fbjni/detail/Iterator-inl.h similarity index 89% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/Iterator-inl.h rename to libs/fbjni/cxx/fbjni/detail/Iterator-inl.h index c056e16af..d915c69fb 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/Iterator-inl.h +++ b/libs/fbjni/cxx/fbjni/detail/Iterator-inl.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ #pragma once @@ -33,7 +42,7 @@ struct IteratorHelper : public JavaClass> { value_type next() { static auto elementField = JavaBase_::javaClassStatic()->template getField("mElement"); - return dynamic_ref_cast(JavaBase_::getFieldValue(elementField)); + return dynamic_ref_cast>(JavaBase_::getFieldValue(elementField)); } static void reset(value_type& v) { diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/Iterator.h b/libs/fbjni/cxx/fbjni/detail/Iterator.h similarity index 87% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/Iterator.h rename to libs/fbjni/cxx/fbjni/detail/Iterator.h index 0da2c3623..02c5c4607 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/Iterator.h +++ b/libs/fbjni/cxx/fbjni/detail/Iterator.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ #pragma once diff --git a/libs/fbjni/cxx/fbjni/detail/JWeakReference.h b/libs/fbjni/cxx/fbjni/detail/JWeakReference.h new file mode 100644 index 000000000..433c6f890 --- /dev/null +++ b/libs/fbjni/cxx/fbjni/detail/JWeakReference.h @@ -0,0 +1,49 @@ +/** + * Copyright 2004-present, Facebook, Inc. + * + * 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. + */ + +#pragma once + +#include "CoreClasses.h" + +namespace facebook { +namespace jni { + +/** + * Wrap Java's WeakReference instead of using JNI WeakGlobalRefs. + * A WeakGlobalRef can yield a strong reference even after the object has been + * finalized. See comment in the djinni library. + * https://github.com/dropbox/djinni/blob/master/support-lib/jni/djinni_support.hpp + */ +template +class JWeakReference : public JavaClass> { + + typedef JavaClass> JavaBase_; + + public: + static constexpr const char* kJavaDescriptor = "Ljava/lang/ref/WeakReference;"; + + static local_ref> newInstance(alias_ref object) { + return JavaBase_::newInstance(static_ref_cast(object)); + } + + local_ref get() const { + static const auto method = JavaBase_::javaClassStatic()->template getMethod("get"); + return static_ref_cast(method(JavaBase_::self())); + } +}; + +} +} diff --git a/libs/fbjni/cxx/fbjni/detail/Log.h b/libs/fbjni/cxx/fbjni/detail/Log.h new file mode 100644 index 000000000..dbc57abdf --- /dev/null +++ b/libs/fbjni/cxx/fbjni/detail/Log.h @@ -0,0 +1,77 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +/** @file ALog.h + * + * Very simple (android only) logging. Define LOG_TAG to enable the macros. + */ + +#pragma once + +#ifdef __ANDROID__ + +#include + +namespace facebook { +namespace jni { +namespace log_ { +// the weird name of this namespace is to avoid a conflict with the +// function named log. + +inline void loge(const char* tag, const char* msg) noexcept { + __android_log_write(ANDROID_LOG_ERROR, tag, msg); +} + +template +inline void loge(const char* tag, const char* msg, ARGS... args) noexcept { + __android_log_print(ANDROID_LOG_ERROR, tag, msg, args...); +} + +inline void logf(const char* tag, const char* msg) noexcept { + __android_log_write(ANDROID_LOG_FATAL, tag, msg); +} + +template +inline void logf(const char* tag, const char* msg, ARGS... args) noexcept { + __android_log_print(ANDROID_LOG_FATAL, tag, msg, args...); +} + +template +[[noreturn]] +inline void logassert(const char* tag, const char* msg, ARGS... args) noexcept { + __android_log_assert(0, tag, msg, args...); +} + + +#ifdef LOG_TAG +# define FBJNI_LOGE(...) ::facebook::jni::log_::loge(LOG_TAG, __VA_ARGS__) +# define FBJNI_LOGF(...) ::facebook::jni::log_::logf(LOG_TAG, __VA_ARGS__) +# define FBJNI_ASSERT(cond) do { if (!(cond)) ::facebook::jni::log_::logassert(LOG_TAG, "%s", #cond); } while(0) +#else +# define FBJNI_LOGE(...) ::facebook::jni::log_::loge("log", __VA_ARGS__) +# define FBJNI_LOGF(...) ::facebook::jni::log_::logf("log", __VA_ARGS__) +# define FBJNI_ASSERT(cond) do { if (!(cond)) ::facebook::jni::log_::logassert("log", "%s", #cond); } while(0) +#endif + +}}} + +#else +#include + +# define FBJNI_LOGE(...) ((void)0) +# define FBJNI_LOGF(...) (abort()) +# define FBJNI_ASSERT(cond) ((void)0) +#endif diff --git a/libs/fbjni/cxx/fbjni/detail/Meta-forward.h b/libs/fbjni/cxx/fbjni/detail/Meta-forward.h new file mode 100644 index 000000000..84b015249 --- /dev/null +++ b/libs/fbjni/cxx/fbjni/detail/Meta-forward.h @@ -0,0 +1,43 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +#pragma once + +namespace facebook { +namespace jni { + +template +class JMethod; +template +class JStaticMethod; +template +class JNonvirtualMethod; +template +struct JConstructor; +template +class JField; +template +class JStaticField; + +/// Type traits for Java types (currently providing Java type descriptors) +template +struct jtype_traits; + +/// Type traits for Java methods (currently providing Java type descriptors) +template +struct jmethod_traits; + +}} diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/Meta-inl.h b/libs/fbjni/cxx/fbjni/detail/Meta-inl.h similarity index 84% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/Meta-inl.h rename to libs/fbjni/cxx/fbjni/detail/Meta-inl.h index ff4c016be..bd7f5bfdb 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/Meta-inl.h +++ b/libs/fbjni/cxx/fbjni/detail/Meta-inl.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ #pragma once @@ -15,10 +24,6 @@ #include "References.h" #include "Boxed.h" -#if defined(__ANDROID__) -#include -#endif - namespace facebook { namespace jni { @@ -63,31 +68,10 @@ local_ref::javaobject> makeArgsArray(Args... args) { return arr; } - -inline bool needsSlowPath(alias_ref obj) { -#if defined(__ANDROID__) - // On Android 6.0, art crashes when attempting to call a function on a Proxy. - // So, when we detect that case we must use the safe, slow workaround. That is, - // we resolve the method id to the corresponding java.lang.reflect.Method object - // and make the call via it's invoke() method. - static auto android_sdk = ([] { - char sdk_version_str[PROP_VALUE_MAX]; - __system_property_get("ro.build.version.sdk", sdk_version_str); - return atoi(sdk_version_str); - })(); - static auto is_bad_android = android_sdk == 23; - if (!is_bad_android) return false; - static auto proxy_class = findClassStatic("java/lang/reflect/Proxy"); - return obj->isInstanceOf(proxy_class); -#else - return false; -#endif -} - } template -inline void JMethod::operator()(alias_ref self, Args... args) { +inline void JMethod::operator()(alias_ref self, Args... args) const { const auto env = Environment::current(); env->CallVoidMethod( self.get(), @@ -98,10 +82,10 @@ inline void JMethod::operator()(alias_ref self, Args... #pragma push_macro("DEFINE_PRIMITIVE_CALL") #undef DEFINE_PRIMITIVE_CALL -#define DEFINE_PRIMITIVE_CALL(TYPE, METHOD, CLASS) \ +#define DEFINE_PRIMITIVE_CALL(TYPE, METHOD) \ template \ -inline TYPE JMethod::operator()(alias_ref self, Args... args) { \ - const auto env = internal::getEnv(); \ +inline TYPE JMethod::operator()(alias_ref self, Args... args) const { \ + const auto env = Environment::current(); \ auto result = env->Call ## METHOD ## Method( \ self.get(), \ getId(), \ @@ -110,14 +94,14 @@ inline TYPE JMethod::operator()(alias_ref self, Args... return result; \ } -DEFINE_PRIMITIVE_CALL(jboolean, Boolean, JBoolean) -DEFINE_PRIMITIVE_CALL(jbyte, Byte, JByte) -DEFINE_PRIMITIVE_CALL(jchar, Char, JCharacter) -DEFINE_PRIMITIVE_CALL(jshort, Short, JShort) -DEFINE_PRIMITIVE_CALL(jint, Int, JInteger) -DEFINE_PRIMITIVE_CALL(jlong, Long, JLong) -DEFINE_PRIMITIVE_CALL(jfloat, Float, JFloat) -DEFINE_PRIMITIVE_CALL(jdouble, Double, JDouble) +DEFINE_PRIMITIVE_CALL(jboolean, Boolean) +DEFINE_PRIMITIVE_CALL(jbyte, Byte) +DEFINE_PRIMITIVE_CALL(jchar, Char) +DEFINE_PRIMITIVE_CALL(jshort, Short) +DEFINE_PRIMITIVE_CALL(jint, Int) +DEFINE_PRIMITIVE_CALL(jlong, Long) +DEFINE_PRIMITIVE_CALL(jfloat, Float) +DEFINE_PRIMITIVE_CALL(jdouble, Double) #pragma pop_macro("DEFINE_PRIMITIVE_CALL") /// JMethod specialization for references that wraps the return value in a @ref local_ref @@ -132,13 +116,13 @@ class JMethod : public JMethodBase { JMethod(const JMethod& other) noexcept = default; /// Invoke a method and return a local reference wrapping the result - local_ref operator()(alias_ref self, Args... args); + local_ref operator()(alias_ref self, Args... args) const; friend class JClass; }; template -inline auto JMethod::operator()(alias_ref self, Args... args) -> local_ref { +inline auto JMethod::operator()(alias_ref self, Args... args) const -> local_ref { const auto env = Environment::current(); auto result = env->CallObjectMethod( self.get(), @@ -149,8 +133,8 @@ inline auto JMethod::operator()(alias_ref self, Args... arg } template -inline void JStaticMethod::operator()(alias_ref cls, Args... args) { - const auto env = internal::getEnv(); +inline void JStaticMethod::operator()(alias_ref cls, Args... args) const { + const auto env = Environment::current(); env->CallStaticVoidMethod( cls.get(), getId(), @@ -162,8 +146,8 @@ inline void JStaticMethod::operator()(alias_ref cls, Args #undef DEFINE_PRIMITIVE_STATIC_CALL #define DEFINE_PRIMITIVE_STATIC_CALL(TYPE, METHOD) \ template \ -inline TYPE JStaticMethod::operator()(alias_ref cls, Args... args) { \ - const auto env = internal::getEnv(); \ +inline TYPE JStaticMethod::operator()(alias_ref cls, Args... args) const { \ + const auto env = Environment::current(); \ auto result = env->CallStatic ## METHOD ## Method( \ cls.get(), \ getId(), \ @@ -194,8 +178,8 @@ class JStaticMethod : public JMethodBase { JStaticMethod(const JStaticMethod& other) noexcept = default; /// Invoke a method and return a local reference wrapping the result - local_ref operator()(alias_ref cls, Args... args) { - const auto env = internal::getEnv(); + local_ref operator()(alias_ref cls, Args... args) const { + const auto env = Environment::current(); auto result = env->CallStaticObjectMethod( cls.get(), getId(), @@ -209,8 +193,8 @@ class JStaticMethod : public JMethodBase { template inline void -JNonvirtualMethod::operator()(alias_ref self, alias_ref cls, Args... args) { - const auto env = internal::getEnv(); +JNonvirtualMethod::operator()(alias_ref self, alias_ref cls, Args... args) const { + const auto env = Environment::current(); env->CallNonvirtualVoidMethod( self.get(), cls.get(), @@ -224,8 +208,8 @@ JNonvirtualMethod::operator()(alias_ref self, alias_ref< #define DEFINE_PRIMITIVE_NON_VIRTUAL_CALL(TYPE, METHOD) \ template \ inline TYPE \ -JNonvirtualMethod::operator()(alias_ref self, alias_ref cls, Args... args) { \ - const auto env = internal::getEnv(); \ +JNonvirtualMethod::operator()(alias_ref self, alias_ref cls, Args... args) const { \ + const auto env = Environment::current(); \ auto result = env->CallNonvirtual ## METHOD ## Method( \ self.get(), \ cls.get(), \ @@ -256,8 +240,8 @@ class JNonvirtualMethod : public JMethodBase { JNonvirtualMethod(const JNonvirtualMethod& other) noexcept = default; /// Invoke a method and return a local reference wrapping the result - local_ref operator()(alias_ref self, alias_ref cls, Args... args){ - const auto env = internal::getEnv(); + local_ref operator()(alias_ref self, alias_ref cls, Args... args) const { + const auto env = Environment::current(); auto result = env->CallNonvirtualObjectMethod( self.get(), cls.get(), @@ -306,13 +290,13 @@ inline jfieldID JField::getId() const noexcept { #define DEFINE_FIELD_PRIMITIVE_GET_SET(TYPE, METHOD) \ template<> \ inline TYPE JField::get(jobject object) const noexcept { \ - const auto env = internal::getEnv(); \ + const auto env = Environment::current(); \ return env->Get ## METHOD ## Field(object, field_id_); \ } \ \ template<> \ inline void JField::set(jobject object, TYPE value) noexcept { \ - const auto env = internal::getEnv(); \ + const auto env = Environment::current(); \ env->Set ## METHOD ## Field(object, field_id_, value); \ } @@ -328,12 +312,12 @@ DEFINE_FIELD_PRIMITIVE_GET_SET(jdouble, Double) template inline T JField::get(jobject object) const noexcept { - return static_cast(internal::getEnv()->GetObjectField(object, field_id_)); + return static_cast(Environment::current()->GetObjectField(object, field_id_)); } template inline void JField::set(jobject object, T value) noexcept { - internal::getEnv()->SetObjectField(object, field_id_, static_cast(value)); + Environment::current()->SetObjectField(object, field_id_, static_cast(value)); } // JStaticField ///////////////////////////////////////////////////////////////////////////////// @@ -358,13 +342,13 @@ inline jfieldID JStaticField::getId() const noexcept { #define DEFINE_STATIC_FIELD_PRIMITIVE_GET_SET(TYPE, METHOD) \ template<> \ inline TYPE JStaticField::get(jclass jcls) const noexcept { \ - const auto env = internal::getEnv(); \ + const auto env = Environment::current(); \ return env->GetStatic ## METHOD ## Field(jcls, field_id_); \ } \ \ template<> \ inline void JStaticField::set(jclass jcls, TYPE value) noexcept { \ - const auto env = internal::getEnv(); \ + const auto env = Environment::current(); \ env->SetStatic ## METHOD ## Field(jcls, field_id_, value); \ } @@ -380,13 +364,13 @@ DEFINE_STATIC_FIELD_PRIMITIVE_GET_SET(jdouble, Double) template inline T JStaticField::get(jclass jcls) const noexcept { - const auto env = internal::getEnv(); + const auto env = Environment::current(); return static_cast(env->GetStaticObjectField(jcls, field_id_)); } template inline void JStaticField::set(jclass jcls, T value) noexcept { - internal::getEnv()->SetStaticObjectField(jcls, field_id_, value); + Environment::current()->SetStaticObjectField(jcls, field_id_, value); } diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/Meta.h b/libs/fbjni/cxx/fbjni/detail/Meta.h similarity index 93% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/Meta.h rename to libs/fbjni/cxx/fbjni/detail/Meta.h index e9717bf7f..739de84f8 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/Meta.h +++ b/libs/fbjni/cxx/fbjni/detail/Meta.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ /** @file meta.h @@ -81,7 +90,7 @@ class JMethod : public JMethodBase { JMethod() noexcept {}; \ JMethod(const JMethod& other) noexcept = default; \ \ - TYPE operator()(alias_ref self, Args... args); \ + TYPE operator()(alias_ref self, Args... args) const; \ \ friend class JClass; \ } @@ -131,7 +140,7 @@ class JStaticMethod : public JMethodBase { \ JStaticMethod() noexcept {}; \ JStaticMethod(const JStaticMethod& other) noexcept = default; \ \ - TYPE operator()(alias_ref cls, Args... args); \ + TYPE operator()(alias_ref cls, Args... args) const; \ \ friend class JClass; \ } @@ -171,7 +180,7 @@ class JNonvirtualMethod : public JMethodBase { \ JNonvirtualMethod() noexcept {}; \ JNonvirtualMethod(const JNonvirtualMethod& other) noexcept = default; \ \ - TYPE operator()(alias_ref self, alias_ref cls, Args... args); \ + TYPE operator()(alias_ref self, alias_ref cls, Args... args) const; \ \ friend class JClass; \ } diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/MetaConvert.h b/libs/fbjni/cxx/fbjni/detail/MetaConvert.h similarity index 64% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/MetaConvert.h rename to libs/fbjni/cxx/fbjni/detail/MetaConvert.h index 33027c7e9..71ea8b157 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/MetaConvert.h +++ b/libs/fbjni/cxx/fbjni/detail/MetaConvert.h @@ -1,4 +1,18 @@ -// Copyright 2004-present Facebook. All Rights Reserved. +/** + * Copyright 2004-present, Facebook, Inc. + * + * 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. + */ #pragma once @@ -95,7 +109,21 @@ template struct Convert> { typedef JniType jniType; // No automatic synthesis of global_ref - static jniType toJniRet(global_ref t) { + static jniType toJniRet(global_ref&& t) { + // If this gets called, ownership the global_ref was passed in here. (It's + // probably a copy of a persistent global_ref made when a function was + // declared to return a global_ref, but it could moved out or otherwise not + // referenced elsewhere. Doesn't matter.) Either way, the only safe way + // to return it is to make a local_ref, release it, and return the + // underlying local jobject. + auto ret = make_local(t); + return ret.release(); + } + static jniType toJniRet(const global_ref& t) { + // If this gets called, the function was declared to return const&. We + // have a ref to a global_ref whose lifetime will exceed this call, so we + // can just get the underlying jobject and return it to java without + // needing to make a local_ref. return t.get(); } static jniType toCall(global_ref t) { diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/ReferenceAllocators-inl.h b/libs/fbjni/cxx/fbjni/detail/ReferenceAllocators-inl.h similarity index 61% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/ReferenceAllocators-inl.h rename to libs/fbjni/cxx/fbjni/detail/ReferenceAllocators-inl.h index 65b9828c6..3a42d364c 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/ReferenceAllocators-inl.h +++ b/libs/fbjni/cxx/fbjni/detail/ReferenceAllocators-inl.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ #pragma once @@ -11,6 +20,8 @@ #include #include +#include "Environment.h" + namespace facebook { namespace jni { @@ -19,7 +30,8 @@ namespace internal { // Statistics mostly provided for test (only updated if FBJNI_DEBUG_REFS is defined) struct ReferenceStats { - std::atomic_uint locals_deleted, globals_deleted, weaks_deleted; + std::atomic_uint locals_created, globals_created, weaks_created, + locals_deleted, globals_deleted, weaks_deleted; void reset() noexcept; }; @@ -33,7 +45,10 @@ extern ReferenceStats g_reference_stats; inline jobject LocalReferenceAllocator::newReference(jobject original) const { internal::dbglog("Local new: %p", original); - auto ref = internal::getEnv()->NewLocalRef(original); + #ifdef FBJNI_DEBUG_REFS + ++internal::g_reference_stats.locals_created; + #endif + auto ref = Environment::current()->NewLocalRef(original); FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); return ref; } @@ -46,15 +61,12 @@ inline void LocalReferenceAllocator::deleteReference(jobject reference) const no ++internal::g_reference_stats.locals_deleted; #endif assert(verifyReference(reference)); - internal::getEnv()->DeleteLocalRef(reference); + Environment::current()->DeleteLocalRef(reference); } } inline bool LocalReferenceAllocator::verifyReference(jobject reference) const noexcept { - if (!reference || !internal::doesGetObjectRefTypeWork()) { - return true; - } - return internal::getEnv()->GetObjectRefType(reference) == JNILocalRefType; + return isObjectRefType(reference, JNILocalRefType); } @@ -62,7 +74,10 @@ inline bool LocalReferenceAllocator::verifyReference(jobject reference) const no inline jobject GlobalReferenceAllocator::newReference(jobject original) const { internal::dbglog("Global new: %p", original); - auto ref = internal::getEnv()->NewGlobalRef(original); + #ifdef FBJNI_DEBUG_REFS + ++internal::g_reference_stats.globals_created; + #endif + auto ref = Environment::current()->NewGlobalRef(original); FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); return ref; } @@ -75,15 +90,12 @@ inline void GlobalReferenceAllocator::deleteReference(jobject reference) const n ++internal::g_reference_stats.globals_deleted; #endif assert(verifyReference(reference)); - internal::getEnv()->DeleteGlobalRef(reference); + Environment::current()->DeleteGlobalRef(reference); } } inline bool GlobalReferenceAllocator::verifyReference(jobject reference) const noexcept { - if (!reference || !internal::doesGetObjectRefTypeWork()) { - return true; - } - return internal::getEnv()->GetObjectRefType(reference) == JNIGlobalRefType; + return isObjectRefType(reference, JNIGlobalRefType); } @@ -91,7 +103,10 @@ inline bool GlobalReferenceAllocator::verifyReference(jobject reference) const n inline jobject WeakGlobalReferenceAllocator::newReference(jobject original) const { internal::dbglog("Weak global new: %p", original); - auto ref = internal::getEnv()->NewWeakGlobalRef(original); + #ifdef FBJNI_DEBUG_REFS + ++internal::g_reference_stats.weaks_created; + #endif + auto ref = Environment::current()->NewWeakGlobalRef(original); FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); return ref; } @@ -104,15 +119,12 @@ inline void WeakGlobalReferenceAllocator::deleteReference(jobject reference) con ++internal::g_reference_stats.weaks_deleted; #endif assert(verifyReference(reference)); - internal::getEnv()->DeleteWeakGlobalRef(reference); + Environment::current()->DeleteWeakGlobalRef(reference); } } inline bool WeakGlobalReferenceAllocator::verifyReference(jobject reference) const noexcept { - if (!reference || !internal::doesGetObjectRefTypeWork()) { - return true; - } - return internal::getEnv()->GetObjectRefType(reference) == JNIWeakGlobalRefType; + return isObjectRefType(reference, JNIWeakGlobalRefType); } }} diff --git a/libs/fbjni/cxx/fbjni/detail/ReferenceAllocators.h b/libs/fbjni/cxx/fbjni/detail/ReferenceAllocators.h new file mode 100644 index 000000000..7278ed094 --- /dev/null +++ b/libs/fbjni/cxx/fbjni/detail/ReferenceAllocators.h @@ -0,0 +1,64 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +/** + * @file ReferenceAllocators.h + * + * Reference allocators are used to create and delete various classes of JNI references (local, + * global, and weak global). + */ + +#pragma once + +#include "Common.h" + +namespace facebook { namespace jni { + +/// Allocator that handles local references +class LocalReferenceAllocator { + public: + jobject newReference(jobject original) const; + void deleteReference(jobject reference) const noexcept; + bool verifyReference(jobject reference) const noexcept; +}; + +/// Allocator that handles global references +class GlobalReferenceAllocator { + public: + jobject newReference(jobject original) const; + void deleteReference(jobject reference) const noexcept; + bool verifyReference(jobject reference) const noexcept; +}; + +/// Allocator that handles weak global references +class WeakGlobalReferenceAllocator { + public: + jobject newReference(jobject original) const; + void deleteReference(jobject reference) const noexcept; + bool verifyReference(jobject reference) const noexcept; +}; + +/** + * @return Helper based on GetObjectRefType. Since this isn't defined + * on all versions of Java or Android, if the type can't be + * determined, this returns true. If reference is nullptr, returns + * true. + */ +bool isObjectRefType(jobject reference, jobjectRefType refType); + +}} + +#include "ReferenceAllocators-inl.h" diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/References-forward.h b/libs/fbjni/cxx/fbjni/detail/References-forward.h similarity index 69% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/References-forward.h rename to libs/fbjni/cxx/fbjni/detail/References-forward.h index 58ce511d5..9b68d614f 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/References-forward.h +++ b/libs/fbjni/cxx/fbjni/detail/References-forward.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ #pragma once diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/References-inl.h b/libs/fbjni/cxx/fbjni/detail/References-inl.h similarity index 92% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/References-inl.h rename to libs/fbjni/cxx/fbjni/detail/References-inl.h index 6bdc18152..7fc17671e 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/References-inl.h +++ b/libs/fbjni/cxx/fbjni/detail/References-inl.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ #pragma once @@ -484,22 +493,25 @@ template auto dynamic_ref_cast(const RefType& ref) -> enable_if_t(), decltype(static_ref_cast(ref))> { - if (! ref) { + if (!ref) { return decltype(static_ref_cast(ref))(); } - std::string target_class_name{jtype_traits::base_name()}; + static alias_ref target_class = findClassStatic(jtype_traits::base_name().c_str()); + if (!target_class) { + throwNewJavaException("java/lang/ClassCastException", + "Could not find class %s.", + jtype_traits::base_name().c_str()); - // If not found, will throw an exception. - alias_ref target_class = findClassStatic(target_class_name.c_str()); + } local_ref source_class = ref->getClass(); - if ( ! source_class->isAssignableFrom(target_class)) { + if (!target_class->isAssignableFrom(source_class)) { throwNewJavaException("java/lang/ClassCastException", "Tried to cast from %s to %s.", source_class->toString().c_str(), - target_class_name.c_str()); + jtype_traits::base_name().c_str()); } return static_ref_cast(ref); diff --git a/libs/fbjni/cxx/fbjni/detail/References.cpp b/libs/fbjni/cxx/fbjni/detail/References.cpp new file mode 100644 index 000000000..6062c49ca --- /dev/null +++ b/libs/fbjni/cxx/fbjni/detail/References.cpp @@ -0,0 +1,75 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +#include "References.h" + +namespace facebook { +namespace jni { + +JniLocalScope::JniLocalScope(JNIEnv* env, jint capacity) + : env_(env) { + hasFrame_ = false; + auto pushResult = env->PushLocalFrame(capacity); + FACEBOOK_JNI_THROW_EXCEPTION_IF(pushResult < 0); + hasFrame_ = true; +} + +JniLocalScope::~JniLocalScope() { + if (hasFrame_) { + env_->PopLocalFrame(nullptr); + } +} + +namespace { + +#ifdef __ANDROID__ + +int32_t getAndroidApiLevel() { + auto cls = findClassLocal("android/os/Build$VERSION"); + auto fld = cls->getStaticField("SDK_INT"); + if (fld) { + return cls->getStaticFieldValue(fld); + } + return 0; +} + +bool doesGetObjectRefTypeWork() { + auto level = getAndroidApiLevel(); + return level >= 14; +} + +#else + +bool doesGetObjectRefTypeWork() { + auto jni_version = Environment::current()->GetVersion(); + return jni_version >= JNI_VERSION_1_6; +} + +#endif + +} + +bool isObjectRefType(jobject reference, jobjectRefType refType) { + static bool getObjectRefTypeWorks = doesGetObjectRefTypeWork(); + + return + !reference || + !getObjectRefTypeWorks || + Environment::current()->GetObjectRefType(reference) == refType; +} + +} +} diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/References.h b/libs/fbjni/cxx/fbjni/detail/References.h similarity index 96% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/References.h rename to libs/fbjni/cxx/fbjni/detail/References.h index b3484e5ed..2cd0d8482 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/References.h +++ b/libs/fbjni/cxx/fbjni/detail/References.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ @@ -75,8 +84,6 @@ #include -#include - #include "ReferenceAllocators.h" #include "TypeTraits.h" #include "References-forward.h" @@ -338,7 +345,7 @@ class weak_ref : public base_owned_ref { : base_owned_ref{} {} /// Create a null reference - explicit weak_ref(std::nullptr_t) noexcept + /* implicit */ weak_ref(std::nullptr_t) noexcept : base_owned_ref{nullptr} {} /// Copy constructor (note creates a new reference) @@ -407,7 +414,7 @@ class basic_strong_ref : public base_owned_ref { : base_owned_ref{} {} /// Create a null reference - explicit basic_strong_ref(std::nullptr_t) noexcept + /* implicit */ basic_strong_ref(std::nullptr_t) noexcept : base_owned_ref{nullptr} {} /// Copy constructor (note creates a new reference) @@ -494,7 +501,7 @@ class alias_ref { alias_ref() noexcept; /// Create a null reference - alias_ref(std::nullptr_t) noexcept; + /* implicit */ alias_ref(std::nullptr_t) noexcept; /// Copy constructor alias_ref(const alias_ref& other) noexcept; @@ -555,7 +562,7 @@ class alias_ref { * This is useful when you have a call which is initiated from C++-land, and therefore * doesn't automatically get a local JNI frame managed for you by the JNI framework. */ -class FBEXPORT JniLocalScope { +class JniLocalScope { public: JniLocalScope(JNIEnv* p_env, jint capacity); ~JniLocalScope(); diff --git a/libs/fbjni/cxx/fbjni/detail/Registration-inl.h b/libs/fbjni/cxx/fbjni/detail/Registration-inl.h new file mode 100644 index 000000000..f7171a6a3 --- /dev/null +++ b/libs/fbjni/cxx/fbjni/detail/Registration-inl.h @@ -0,0 +1,156 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +#pragma once + +#include "Exceptions.h" +#include "Hybrid.h" + +namespace facebook { +namespace jni { + +namespace detail { + +#ifdef __i386__ +// X86 ABI forces 16 byte stack allignment on calls. Unfortunately +// sometimes Dalvik chooses not to obey the ABI: +// - https://code.google.com/p/android/issues/detail?id=61012 +// - https://android.googlesource.com/platform/ndk/+/81696d2%5E!/ +// Therefore, we tell the compiler to re-align the stack on entry +// to our JNI functions. +#define JNI_ENTRY_POINT __attribute__((force_align_arg_pointer)) +#else +#define JNI_ENTRY_POINT +#endif + +template +struct CreateDefault { + static R create() { + return R{}; + } +}; + +template <> +struct CreateDefault { + static void create() {} +}; + +template +using Converter = Convert::type>; + +template +struct WrapForVoidReturn { + static typename Converter::jniType call(Args&&... args) { + return Converter::toJniRet(func(std::forward(args)...)); + } +}; + +template +struct WrapForVoidReturn { + static void call(Args&&... args) { + func(std::forward(args)...); + } +}; + +// registration wrapper for legacy JNI-style functions +template +struct BareJniWrapper { + JNI_ENTRY_POINT static R call(JNIEnv* env, jobject obj, Args... args) { + detail::JniEnvCacher jec(env); + try { + return (*func)(env, static_cast>(obj), args...); + } catch (...) { + translatePendingCppExceptionToJavaException(); + return CreateDefault::create(); + } + } +}; + +// registration wrappers for functions, with autoconversion of arguments. +template +struct FunctionWrapper { + using jniRet = typename Converter::jniType; + JNI_ENTRY_POINT static jniRet call(JNIEnv* env, jobject obj, typename Converter::jniType... args) { + detail::JniEnvCacher jec(env); + try { + return WrapForVoidReturn, Args...>::call( + static_cast>(obj), Converter::fromJni(args)...); + } catch (...) { + translatePendingCppExceptionToJavaException(); + return CreateDefault::create(); + } + } +}; + +// registration wrappers for non-static methods, with autoconvertion of arguments. +template +struct MethodWrapper { + using jhybrid = typename C::jhybridobject; + static R dispatch(alias_ref ref, Args&&... args) { + try { + // This is usually a noop, but if the hybrid object is a + // base class of other classes which register JNI methods, + // this will get the right type for the registered method. + auto cobj = static_cast(ref->cthis()); + return (cobj->*method)(std::forward(args)...); + } catch (const std::exception& ex) { + C::mapException(ex); + throw; + } + } + + JNI_ENTRY_POINT static typename Converter::jniType call( + JNIEnv* env, jobject obj, typename Converter::jniType... args) { + return FunctionWrapper, Args&&...), dispatch, jhybrid, R, Args...>::call(env, obj, args...); + } +}; + +template +inline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(JNIEnv*, C, Args... args)) { + // This intentionally erases the real type; JNI will do it anyway + return reinterpret_cast(&(BareJniWrapper::call)); +} + +template +inline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(alias_ref, Args... args)) { + // This intentionally erases the real type; JNI will do it anyway + return reinterpret_cast(&(FunctionWrapper::call)); +} + +template +inline NativeMethodWrapper* exceptionWrapJNIMethod(R (C::*method0)(Args... args)) { + // This intentionally erases the real type; JNI will do it anyway + return reinterpret_cast(&(MethodWrapper::call)); +} + +template +inline std::string makeDescriptor(R (*)(JNIEnv*, C, Args... args)) { + return jmethod_traits::descriptor(); +} + +template +inline std::string makeDescriptor(R (*)(alias_ref, Args... args)) { + return jmethod_traits_from_cxx::descriptor(); +} + +template +inline std::string makeDescriptor(R (C::*)(Args... args)) { + return jmethod_traits_from_cxx::descriptor(); +} + +} + +}} diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/Registration.h b/libs/fbjni/cxx/fbjni/detail/Registration.h similarity index 76% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/Registration.h rename to libs/fbjni/cxx/fbjni/detail/Registration.h index 654fdab2c..924538757 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/Registration.h +++ b/libs/fbjni/cxx/fbjni/detail/Registration.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ #pragma once @@ -18,28 +27,14 @@ namespace detail { // This uses the real JNI function as a non-type template parameter to // cause a (static member) function to exist with the same signature, // but with try/catch exception translation. -template -NativeMethodWrapper* exceptionWrapJNIMethod(void (*func0)(JNIEnv*, jobject, Args... args)); - -// Same as above, but for non-void return types. template NativeMethodWrapper* exceptionWrapJNIMethod(R (*func0)(JNIEnv*, jobject, Args... args)); // Automatically wrap object argument, and don't take env explicitly. -template -NativeMethodWrapper* exceptionWrapJNIMethod(void (*func0)(alias_ref, Args... args)); - -// Automatically wrap object argument, and don't take env explicitly, -// non-void return type. template NativeMethodWrapper* exceptionWrapJNIMethod(R (*func0)(alias_ref, Args... args)); -// Extract C++ instance from object, and invoke given method on it. -template -NativeMethodWrapper* exceptionWrapJNIMethod(void (C::*method0)(Args... args)); - // Extract C++ instance from object, and invoke given method on it, -// non-void return type template NativeMethodWrapper* exceptionWrapJNIMethod(R (C::*method0)(Args... args)); diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/TypeTraits.h b/libs/fbjni/cxx/fbjni/detail/TypeTraits.h similarity index 88% rename from libs/fbjni/src/main/cpp/include/fb/fbjni/TypeTraits.h rename to libs/fbjni/cxx/fbjni/detail/TypeTraits.h index 36c8bec15..dc9fbb019 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/TypeTraits.h +++ b/libs/fbjni/cxx/fbjni/detail/TypeTraits.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ #pragma once diff --git a/libs/fbjni/src/main/cpp/jni/LocalString.cpp b/libs/fbjni/cxx/fbjni/detail/utf8.cpp similarity index 76% rename from libs/fbjni/src/main/cpp/jni/LocalString.cpp rename to libs/fbjni/cxx/fbjni/detail/utf8.cpp index 20745519d..2cda26d6d 100644 --- a/libs/fbjni/src/main/cpp/jni/LocalString.cpp +++ b/libs/fbjni/cxx/fbjni/detail/utf8.cpp @@ -1,15 +1,22 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ -#include -#include -#include +#include "utf8.h" -#include +#include "Log.h" namespace facebook { namespace jni { @@ -23,7 +30,9 @@ const uint16_t kUtf16HighSubHighBoundary = 0xDC00; const uint16_t kUtf16LowSubHighBoundary = 0xE000; inline void encode3ByteUTF8(char32_t code, uint8_t* out) { - FBASSERTMSGF((code & 0xffff0000) == 0, "3 byte utf-8 encodings only valid for up to 16 bits"); + if ((code & 0xffff0000) != 0) { + FBJNI_LOGF("3 byte utf-8 encodings only valid for up to 16 bits"); + } out[0] = 0xE0 | (code >> 12); out[1] = 0x80 | ((code >> 6) & 0x3F); @@ -37,7 +46,9 @@ inline char32_t decode3ByteUTF8(const uint8_t* in) { } inline void encode4ByteUTF8(char32_t code, std::string& out, size_t offset) { - FBASSERTMSGF((code & 0xfff80000) == 0, "4 byte utf-8 encodings only valid for up to 21 bits"); + if ((code & 0xfff80000) != 0) { + FBJNI_LOGF("4 byte utf-8 encodings only valid for up to 21 bits"); + } out[offset] = (char) (0xF0 | (code >> 18)); out[offset + 1] = (char) (0x80 | ((code >> 12) & 0x3F)); @@ -101,9 +112,13 @@ void utf8ToModifiedUTF8(const uint8_t* utf8, size_t len, uint8_t* modified, size { size_t j = 0; for (size_t i = 0; i < len; ) { - FBASSERTMSGF(j < modifiedBufLen, "output buffer is too short"); + if (j >= modifiedBufLen) { + FBJNI_LOGF("output buffer is too short"); + } if (utf8[i] == 0) { - FBASSERTMSGF(j + 1 < modifiedBufLen, "output buffer is too short"); + if (j + 1 >= modifiedBufLen) { + FBJNI_LOGF("output buffer is too short"); + } modified[j] = 0xc0; modified[j + 1] = 0x80; i += 1; @@ -143,14 +158,18 @@ void utf8ToModifiedUTF8(const uint8_t* utf8, size_t len, uint8_t* modified, size } // encode each as a 3 byte surrogate value - FBASSERTMSGF(j + 5 < modifiedBufLen, "output buffer is too short"); + if (j + 5 >= modifiedBufLen) { + FBJNI_LOGF("output buffer is too short"); + } encode3ByteUTF8(first, modified + j); encode3ByteUTF8(second, modified + j + 3); i += 4; j += 6; } - FBASSERTMSGF(j < modifiedBufLen, "output buffer is too short"); + if (j >= modifiedBufLen) { + FBJNI_LOGF("output buffer is too short"); + } modified[j++] = '\0'; } @@ -265,46 +284,5 @@ std::string utf16toUTF8(const uint16_t* utf16String, size_t utf16StringLen) noex } } - -LocalString::LocalString(const std::string& str) -{ - size_t modlen = detail::modifiedLength(str); - if (modlen == str.size()) { - // no supplementary characters, build jstring from input buffer - m_string = Environment::current()->NewStringUTF(str.data()); - return; - } - auto modified = std::vector(modlen + 1); // allocate extra byte for \0 - detail::utf8ToModifiedUTF8( - reinterpret_cast(str.data()), str.size(), - reinterpret_cast(modified.data()), modified.size()); - m_string = Environment::current()->NewStringUTF(modified.data()); } - -LocalString::LocalString(const char* str) -{ - size_t len; - size_t modlen = detail::modifiedLength(reinterpret_cast(str), &len); - if (modlen == len) { - // no supplementary characters, build jstring from input buffer - m_string = Environment::current()->NewStringUTF(str); - return; - } - auto modified = std::vector(modlen + 1); // allocate extra byte for \0 - detail::utf8ToModifiedUTF8( - reinterpret_cast(str), len, - reinterpret_cast(modified.data()), modified.size()); - m_string = Environment::current()->NewStringUTF(modified.data()); } - -LocalString::~LocalString() { - Environment::current()->DeleteLocalRef(m_string); -} - -std::string fromJString(JNIEnv* env, jstring str) { - auto utf16String = JStringUtf16Extractor(env, str); - auto length = env->GetStringLength(str); - return detail::utf16toUTF8(utf16String, length); -} - -} } diff --git a/libs/fbjni/src/main/cpp/include/jni/LocalString.h b/libs/fbjni/cxx/fbjni/detail/utf8.h similarity index 68% rename from libs/fbjni/src/main/cpp/include/jni/LocalString.h rename to libs/fbjni/cxx/fbjni/detail/utf8.h index e7c648e42..b1b8558db 100644 --- a/libs/fbjni/src/main/cpp/include/jni/LocalString.h +++ b/libs/fbjni/cxx/fbjni/detail/utf8.h @@ -1,8 +1,17 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ #pragma once @@ -11,8 +20,6 @@ #include -#include - namespace facebook { namespace jni { @@ -43,28 +50,18 @@ std::string utf16toUTF8(const uint16_t* utf16Bytes, size_t len) noexcept; // - http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html // - https://docs.oracle.com/javase/6/docs/api/java/io/DataInput.html#modified-utf-8 -class FBEXPORT LocalString { -public: - // Assumes UTF8 encoding and make a required convertion to modified UTF-8 when the string - // contains unicode supplementary characters. - explicit LocalString(const std::string& str); - explicit LocalString(const char* str); - jstring string() const { - return m_string; - } - ~LocalString(); -private: - jstring m_string; -}; - -// JString to UTF16 extractor using RAII idiom +// JString to UTF16 extractor using RAII idiom. Note that the +// ctor/dtor use GetStringCritical/ReleaseStringCritical, so this +// class is subject to the restrictions imposed by those functions. class JStringUtf16Extractor { public: JStringUtf16Extractor(JNIEnv* env, jstring javaString) : env_(env) , javaString_(javaString) + , length_(0) , utf16String_(nullptr) { if (env_ && javaString_) { + length_ = env_->GetStringLength(javaString_); utf16String_ = env_->GetStringCritical(javaString_, nullptr); } } @@ -75,18 +72,20 @@ public: } } - operator const jchar* () const { + const jsize length() const { + return length_; + } + + const jchar* chars() const { return utf16String_; } private: JNIEnv* env_; jstring javaString_; + jsize length_; const jchar* utf16String_; }; -// The string from JNI is converted to standard UTF-8 if the string contains supplementary -// characters. -FBEXPORT std::string fromJString(JNIEnv* env, jstring str); - -} } +} +} diff --git a/libs/fbjni/src/main/cpp/jni/fbjni.cpp b/libs/fbjni/cxx/fbjni/fbjni.cpp similarity index 64% rename from libs/fbjni/src/main/cpp/jni/fbjni.cpp rename to libs/fbjni/cxx/fbjni/fbjni.cpp index 3e38aa725..a8e78a1e9 100644 --- a/libs/fbjni/src/main/cpp/jni/fbjni.cpp +++ b/libs/fbjni/cxx/fbjni/fbjni.cpp @@ -1,40 +1,48 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. +/** + * Copyright 2018-present, Facebook, Inc. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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. */ -#include +#include #include #include -#include -#include + +#include namespace facebook { namespace jni { jint initialize(JavaVM* vm, std::function&& init_fn) noexcept { - static std::once_flag flag{}; // TODO (t7832883): DTRT when we have exception pointers static auto error_msg = std::string{"Failed to initialize fbjni"}; - static auto error_occured = false; - - std::call_once(flag, [vm] { - try { - Environment::initialize(vm); - } catch (std::exception& ex) { - error_occured = true; + static bool error_occured = [vm] { + bool retVal = false; try { - error_msg = std::string{"Failed to initialize fbjni: "} + ex.what(); + Environment::initialize(vm); + } catch (std::exception& ex) { + retVal = true; + try { + error_msg = std::string{"Failed to initialize fbjni: "} + ex.what(); + } catch (...) { + // Ignore, we already have a fall back message + } } catch (...) { - // Ignore, we already have a fall back message + retVal = true; } - } catch (...) { - error_occured = true; - } - }); + return retVal; + }(); try { if (error_occured) { @@ -43,7 +51,7 @@ jint initialize(JavaVM* vm, std::function&& init_fn) noexcept { init_fn(); } catch (const std::exception& e) { - FBLOGE("error %s", e.what()); + FBJNI_LOGE("error %s", e.what()); translatePendingCppExceptionToJavaException(); } catch (...) { translatePendingCppExceptionToJavaException(); @@ -54,19 +62,19 @@ jint initialize(JavaVM* vm, std::function&& init_fn) noexcept { } alias_ref findClassStatic(const char* name) { - const auto env = internal::getEnv(); + const auto env = detail::currentOrNull(); if (!env) { throw std::runtime_error("Unable to retrieve JNIEnv*."); } - auto cls = env->FindClass(name); + local_ref cls = adopt_local(env->FindClass(name)); FACEBOOK_JNI_THROW_EXCEPTION_IF(!cls); - auto leaking_ref = (jclass)env->NewGlobalRef(cls); + auto leaking_ref = (jclass)env->NewGlobalRef(cls.get()); FACEBOOK_JNI_THROW_EXCEPTION_IF(!leaking_ref); return wrap_alias(leaking_ref); } local_ref findClassLocal(const char* name) { - const auto env = internal::getEnv(); + const auto env = detail::currentOrNull(); if (!env) { throw std::runtime_error("Unable to retrieve JNIEnv*."); } @@ -79,17 +87,25 @@ local_ref findClassLocal(const char* name) { // jstring ///////////////////////////////////////////////////////////////////////////////////////// std::string JString::toStdString() const { - const auto env = internal::getEnv(); + const auto env = Environment::current(); auto utf16String = JStringUtf16Extractor(env, self()); - auto length = env->GetStringLength(self()); - return detail::utf16toUTF8(utf16String, length); + return detail::utf16toUTF8(utf16String.chars(), utf16String.length()); +} + +std::u16string JString::toU16String() const { + const auto env = Environment::current(); + auto utf16String = JStringUtf16Extractor(env, self()); + if (!utf16String.chars() || utf16String.length() == 0) { + return {}; + } + return std::u16string(reinterpret_cast(utf16String.chars()), utf16String.length()); } local_ref make_jstring(const char* utf8) { if (!utf8) { return {}; } - const auto env = internal::getEnv(); + const auto env = Environment::current(); size_t len; size_t modlen = detail::modifiedLength(reinterpret_cast(utf8), &len); jstring result; @@ -112,6 +128,18 @@ local_ref make_jstring(const char* utf8) { return adopt_local(result); } +local_ref make_jstring(const std::u16string& utf16) { + if (utf16.empty()) { + return {}; + } + const auto env = Environment::current(); + static_assert( + sizeof(jchar) == sizeof(std::u16string::value_type), + "Expecting jchar to be the same size as std::u16string::CharT"); + jstring result = env->NewString(reinterpret_cast(utf16.c_str()), utf16.size()); + FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); + return adopt_local(result); +} // JniPrimitiveArrayFunctions ////////////////////////////////////////////////////////////////////// @@ -120,50 +148,44 @@ local_ref make_jstring(const char* utf8) { #define DEFINE_PRIMITIVE_METHODS(TYPE, NAME, SMALLNAME) \ \ template<> \ -FBEXPORT \ TYPE* JPrimitiveArray::getElements(jboolean* isCopy) { \ - auto env = internal::getEnv(); \ + auto env = Environment::current(); \ TYPE* res = env->Get ## NAME ## ArrayElements(self(), isCopy); \ FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); \ return res; \ } \ \ template<> \ -FBEXPORT \ void JPrimitiveArray::releaseElements( \ TYPE* elements, jint mode) { \ - auto env = internal::getEnv(); \ + auto env = Environment::current(); \ env->Release ## NAME ## ArrayElements(self(), elements, mode); \ FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); \ } \ \ template<> \ -FBEXPORT \ void JPrimitiveArray::getRegion( \ jsize start, jsize length, TYPE* buf) { \ - auto env = internal::getEnv(); \ + auto env = Environment::current(); \ env->Get ## NAME ## ArrayRegion(self(), start, length, buf); \ FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); \ } \ \ template<> \ -FBEXPORT \ void JPrimitiveArray::setRegion( \ jsize start, jsize length, const TYPE* elements) { \ - auto env = internal::getEnv(); \ + auto env = Environment::current(); \ env->Set ## NAME ## ArrayRegion(self(), start, length, elements); \ FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); \ } \ \ -FBEXPORT \ local_ref make_ ## SMALLNAME ## _array(jsize size) { \ - auto array = internal::getEnv()->New ## NAME ## Array(size); \ + auto array = Environment::current()->New ## NAME ## Array(size); \ FACEBOOK_JNI_THROW_EXCEPTION_IF(!array); \ return adopt_local(array); \ } \ \ template<> \ -FBEXPORT \ local_ref JArray ## NAME::newArray(size_t count) { \ return make_ ## SMALLNAME ## _array(count); \ } \ @@ -179,13 +201,37 @@ DEFINE_PRIMITIVE_METHODS(jfloat, Float, float) DEFINE_PRIMITIVE_METHODS(jdouble, Double, double) #pragma pop_macro("DEFINE_PRIMITIVE_METHODS") +namespace detail { + +detail::BaseHybridClass* HybridDestructor::getNativePointer() { + static auto pointerField = javaClassStatic()->getField("mNativePointer"); + auto* value = reinterpret_cast(getFieldValue(pointerField)); + if (!value) { + throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException"); + } + return value; +} + +void HybridDestructor::setNativePointer( + std::unique_ptr new_value) { + static auto pointerField = javaClassStatic()->getField("mNativePointer"); + auto old_value = std::unique_ptr( + reinterpret_cast(getFieldValue(pointerField))); + if (new_value && old_value) { + FBJNI_LOGF("Attempt to set C++ native pointer twice"); + } + setFieldValue(pointerField, reinterpret_cast(new_value.release())); +} + +} + // Internal debug ///////////////////////////////////////////////////////////////////////////////// namespace internal { -FBEXPORT ReferenceStats g_reference_stats; +ReferenceStats g_reference_stats; -FBEXPORT void facebook::jni::internal::ReferenceStats::reset() noexcept { +void facebook::jni::internal::ReferenceStats::reset() noexcept { locals_deleted = globals_deleted = weaks_deleted = 0; } diff --git a/libs/fbjni/cxx/fbjni/fbjni.h b/libs/fbjni/cxx/fbjni/fbjni.h new file mode 100644 index 000000000..9af170ce0 --- /dev/null +++ b/libs/fbjni/cxx/fbjni/fbjni.h @@ -0,0 +1,32 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/libs/fbjni/cxx/lyra/cxa_throw.cpp b/libs/fbjni/cxx/lyra/cxa_throw.cpp new file mode 100644 index 000000000..e0449d9a5 --- /dev/null +++ b/libs/fbjni/cxx/lyra/cxa_throw.cpp @@ -0,0 +1,116 @@ +/** + * Copyright 2004-present, Facebook, Inc. + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include + +namespace facebook { +namespace lyra { + +namespace { +std::atomic enableBacktraces{true}; +} + +void enableCxaThrowHookBacktraces(bool enable) { + enableBacktraces.store(enable, std::memory_order_relaxed); +} + +[[gnu::noreturn]] void (*original_cxa_throw)(void*, const std::type_info*, void (*) (void *)); + +#if defined(_LIBCPP_VERSION) +[[noreturn]] void cxa_throw(void* obj, const std::type_info* type, void (*destructor) (void *)) { + // lyra doesn't have support yet for libc++. + original_cxa_throw(obj, type, destructor); +} +#else + +using namespace detail; + +namespace { + +const auto traceHolderType = + static_cast(&typeid(ExceptionTraceHolder)); + +// lyra's __cxa_throw attaches stack trace information to thrown exceptions. It basically does: +// 1. capture stack trace +// 2. construct a new type_info struct that: +// a. holds the ExceptionTraceHolder +// b. supports upcasting to lyra::ExceptionTraceHolder* (by just returning the holder member) +// c. acts like the original exception type_info otherwise +// 3. call original __cxa_throw() with original exception pointer, the +// HijackedExceptionTypeInfo, and HijackedExceptionTypeInfo::destructor +// (which will both delete the constructed type info and call the original +// destructor). +struct HijackedExceptionTypeInfo : public abi::__class_type_info { + HijackedExceptionTypeInfo(void* obj, const std::type_info* base, void(*destructor)(void*)) + : abi::__class_type_info{base->name()}, base_{base}, orig_dest_{destructor} { + } + + bool __is_pointer_p() const override { + return base_->__is_pointer_p(); + } + + bool __is_function_p() const override { + return base_->__is_function_p(); + } + + bool __do_catch(const type_info *__thr_type, void **__thr_obj, unsigned __outer) const override { + return base_->__do_catch(__thr_type, __thr_obj, __outer); + } + + bool __do_upcast(const abi::__class_type_info *__target, void **__obj_ptr) const override { + if (__target == traceHolderType) { + *__obj_ptr = (void*)&stack_; + return true; + } + return base_->__do_upcast(__target, __obj_ptr); + } + + static void destructor(void* obj) { + auto exc_ptr = reinterpret_cast(&obj); + auto info = reinterpret_cast(exc_ptr->__cxa_exception_type()); + auto mutable_info = static_cast(const_cast(info)); + mutable_info->orig_dest_(obj); + delete mutable_info; + } + + private: + const std::type_info* base_; + void (*orig_dest_)(void*); + ExceptionTraceHolder stack_; +}; + +} // namespace + +[[noreturn]] void cxa_throw(void* obj, const std::type_info* type, void (*destructor) (void *)) { + if (enableBacktraces.load(std::memory_order_relaxed)) { + if (!type->__do_upcast(traceHolderType, &obj)) { + type = new HijackedExceptionTypeInfo(obj, type, destructor); + destructor = HijackedExceptionTypeInfo::destructor; + } + } + original_cxa_throw(obj, type, destructor); +} + +#endif // libc++ + +} // namespace lyra +} // namespace facebook diff --git a/libs/fbjni/src/main/cpp/lyra/lyra.cpp b/libs/fbjni/cxx/lyra/lyra.cpp similarity index 58% rename from libs/fbjni/src/main/cpp/lyra/lyra.cpp rename to libs/fbjni/cxx/lyra/lyra.cpp index f915ecef2..2a59c2a2e 100644 --- a/libs/fbjni/src/main/cpp/lyra/lyra.cpp +++ b/libs/fbjni/cxx/lyra/lyra.cpp @@ -1,14 +1,33 @@ -// Copyright 2004-present Facebook. All Rights Reserved. +/** + * Copyright 2004-present, Facebook, Inc. + * + * 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. + */ -#include +#include +#include #include +#include +#include #include #include #include #include +#include + using namespace std; namespace facebook { @@ -63,6 +82,27 @@ void captureBacktrace(size_t skip, vector& stackTrace) { BacktraceState state = {skip, stackTrace}; _Unwind_Backtrace(unwindCallback, &state); } + +// this is a pointer to a function +std::atomic gLibraryIdentifierFunction{nullptr}; + +} + +void setLibraryIdentifierFunction(LibraryIdentifierFunctionType func) { + gLibraryIdentifierFunction.store(func, std::memory_order_relaxed); +} + +std::string StackTraceElement::buildId() const { + if (!hasBuildId_) { + auto getBuildId = gLibraryIdentifierFunction.load(std::memory_order_relaxed); + if (getBuildId) { + buildId_ = getBuildId(libraryName()); + } else { + buildId_ = ""; + } + hasBuildId_ = true; + } + return buildId_; } void getStackTrace(vector& stackTrace, size_t skip) { @@ -89,7 +129,6 @@ void getStackTraceSymbols(vector& symbols, ostream& operator<<(ostream& out, const StackTraceElement& elm) { IosFlagsSaver flags{out}; - // TODO(t10748683): Add build id to the output out << "{dso=" << elm.libraryName() << " offset=" << hex << showbase << elm.libraryOffset(); @@ -97,7 +136,7 @@ ostream& operator<<(ostream& out, const StackTraceElement& elm) { out << " func=" << elm.functionName() << "()+" << elm.functionOffset(); } - out << " build-id=" << hex << setw(8) << 0 + out << " build-id=" << hex << setw(8) << elm.buildId() << "}"; return out; @@ -116,5 +155,28 @@ ostream& operator<<(ostream& out, const vector& trace) { return out; } + +void logStackTrace(const vector& trace) { + auto i = 0; + FBJNI_LOGE("Backtrace:"); + for (auto& elm : trace) { + if (!elm.functionName().empty()) { + FBJNI_LOGE(" #%02d |lyra|{dso=%s offset=%#x func=%s+%#x build-id=%s}", + i++, + elm.libraryName().c_str(), + elm.libraryOffset(), + elm.functionName().c_str(), + elm.functionOffset(), + elm.buildId().c_str()); + } else { + FBJNI_LOGE(" #%02d |lyra|{dso=%s offset=%#x build-id=%s}", + i++, + elm.libraryName().c_str(), + elm.libraryOffset(), + elm.buildId().c_str()); + } + } +} + } } diff --git a/libs/fbjni/src/main/cpp/include/fb/lyra.h b/libs/fbjni/cxx/lyra/lyra.h similarity index 67% rename from libs/fbjni/src/main/cpp/include/fb/lyra.h rename to libs/fbjni/cxx/lyra/lyra.h index c60ff27b6..60698d1bb 100644 --- a/libs/fbjni/src/main/cpp/include/fb/lyra.h +++ b/libs/fbjni/cxx/lyra/lyra.h @@ -1,14 +1,25 @@ -// Copyright 2004-present Facebook. All Rights Reserved. +/** + * Copyright 2004-present, Facebook, Inc. + * + * 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. + */ #pragma once #include -#include #include #include -#include - namespace facebook { namespace lyra { @@ -16,17 +27,21 @@ constexpr size_t kDefaultLimit = 64; using InstructionPointer = const void*; -class FBEXPORT StackTraceElement { +class StackTraceElement { public: StackTraceElement(InstructionPointer absoluteProgramCounter, InstructionPointer libraryBase, - InstructionPointer functionAddress, std::string libraryName, + InstructionPointer functionAddress, + std::string libraryName, std::string functionName) : absoluteProgramCounter_{absoluteProgramCounter}, libraryBase_{libraryBase}, functionAddress_{functionAddress}, libraryName_{std::move(libraryName)}, - functionName_{std::move(functionName)} {} + functionName_{std::move(functionName)}, + hasBuildId_{false}, + buildId_{} + {} InstructionPointer libraryBase() const noexcept { return libraryBase_; } @@ -63,14 +78,28 @@ class FBEXPORT StackTraceElement { return absoluteabsoluteProgramCounter - absoluteSymbol; } + std::string buildId() const; private: const InstructionPointer absoluteProgramCounter_; const InstructionPointer libraryBase_; const InstructionPointer functionAddress_; const std::string libraryName_; const std::string functionName_; + + mutable bool hasBuildId_; + mutable std::string buildId_; }; +/** + * If a library identifier function is set, it is passed a libraryName + * for the frame, and returns a library build id string, which will be + * included in the logged stack trace. The most common use for this + * will be correlating stack traces with breakpad identifiers. + */ +typedef std::string (*LibraryIdentifierFunctionType)(const std::string&); + +void setLibraryIdentifierFunction(LibraryIdentifierFunctionType func); + /** * Populate the vector with the current stack trace * @@ -87,8 +116,7 @@ class FBEXPORT StackTraceElement { * * @param skip The number of frames to skip before capturing the trace */ -FBEXPORT void getStackTrace(std::vector& stackTrace, - size_t skip = 0); +void getStackTrace(std::vector& stackTrace, size_t skip = 0); /** * Creates a vector and populates it with the current stack trace @@ -104,7 +132,7 @@ FBEXPORT void getStackTrace(std::vector& stackTrace, * * @limit The maximum number of frames captured */ -FBEXPORT inline std::vector getStackTrace( +inline std::vector getStackTrace( size_t skip = 0, size_t limit = kDefaultLimit) { auto stackTrace = std::vector{}; @@ -121,15 +149,15 @@ FBEXPORT inline std::vector getStackTrace( * * @param stackTrace The input stack trace */ -FBEXPORT void getStackTraceSymbols(std::vector& symbols, - const std::vector& trace); +void getStackTraceSymbols(std::vector& symbols, + const std::vector& trace); /** * Symbolicates a stack trace into a new vector * * @param stackTrace The input stack trace */ -FBEXPORT inline std::vector getStackTraceSymbols( +inline std::vector getStackTraceSymbols( const std::vector& trace) { auto symbols = std::vector{}; getStackTraceSymbols(symbols, trace); @@ -148,7 +176,7 @@ FBEXPORT inline std::vector getStackTraceSymbols( * * @param limit The maximum number of frames captured */ -FBEXPORT inline std::vector getStackTraceSymbols( +inline std::vector getStackTraceSymbols( size_t skip = 0, size_t limit = kDefaultLimit) { return getStackTraceSymbols(getStackTrace(skip + 1, limit)); @@ -157,12 +185,21 @@ FBEXPORT inline std::vector getStackTraceSymbols( /** * Formatting a stack trace element */ -FBEXPORT std::ostream& operator<<(std::ostream& out, const StackTraceElement& elm); +std::ostream& operator<<(std::ostream& out, const StackTraceElement& elm); /** * Formatting a stack trace */ -FBEXPORT std::ostream& operator<<(std::ostream& out, - const std::vector& trace); +std::ostream& operator<<(std::ostream& out, + const std::vector& trace); + +/** + * Log stack trace + * + * Makes it possible to log a trace without using a temporary stream when the + * underlying log API is not stream based. + */ +void logStackTrace(const std::vector& trace); + } } diff --git a/libs/fbjni/cxx/lyra/lyra_breakpad.cpp b/libs/fbjni/cxx/lyra/lyra_breakpad.cpp new file mode 100644 index 000000000..0c810f411 --- /dev/null +++ b/libs/fbjni/cxx/lyra/lyra_breakpad.cpp @@ -0,0 +1,32 @@ +/** + * Copyright 2004-present, Facebook, Inc. + * + * 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. + */ + +#include + +namespace facebook { +namespace lyra { + +/** + * This can be overridden by an implementation capable of looking up + * the breakpad id for logging purposes. +*/ +__attribute__((weak)) +std::string getBreakpadId(const std::string& library) { + return ""; +} + +} +} diff --git a/libs/fbjni/cxx/lyra/lyra_exceptions.cpp b/libs/fbjni/cxx/lyra/lyra_exceptions.cpp new file mode 100644 index 000000000..0664f8047 --- /dev/null +++ b/libs/fbjni/cxx/lyra/lyra_exceptions.cpp @@ -0,0 +1,98 @@ +/** + * Copyright 2004-present, Facebook, Inc. + * + * 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. + */ + +#include + +#include +#include +#include +#include + +#include + +namespace facebook { +namespace lyra { + +using namespace detail; + +namespace { +std::terminate_handler gTerminateHandler; + +const ExceptionTraceHolder* getExceptionTraceHolder(std::exception_ptr ptr) { + try { + std::rethrow_exception(ptr); + } catch (const ExceptionTraceHolder& holder) { + return &holder; + } catch (...) { + return nullptr; + } +} + +void logExceptionAndAbort() { + if (auto ptr = std::current_exception()) { + FBJNI_LOGE("Uncaught exception: %s", toString(ptr).c_str()); + auto trace = getExceptionTraceHolder(ptr); + if (trace) { + logStackTrace(getStackTraceSymbols(trace->stackTrace_)); + } + } + if (gTerminateHandler) { + gTerminateHandler(); + } else { + FBJNI_LOGF("Uncaught exception and no gTerminateHandler set"); + } +} + +const std::vector emptyTrace; +} // namespace + +ExceptionTraceHolder::~ExceptionTraceHolder() {} + +detail::ExceptionTraceHolder::ExceptionTraceHolder() { + // TODO(cjhopman): This should be done more safely (i.e. use preallocated space, etc.). + stackTrace_.reserve(128); + getStackTrace(stackTrace_, 1); +} + + +void ensureRegisteredTerminateHandler() { + static auto initializer = (gTerminateHandler = std::set_terminate(logExceptionAndAbort)); + (void)initializer; +} + +const std::vector& getExceptionTrace(std::exception_ptr ptr) { + auto holder = getExceptionTraceHolder(ptr); + return holder ? holder->stackTrace_ : emptyTrace; +} + +std::string toString(std::exception_ptr ptr) { + if (!ptr) { + return "No exception"; + } + + try { + std::rethrow_exception(ptr); + } catch (std::exception& e) { + std::stringstream ss; + ss << typeid(e).name() << ": " << e.what(); + return ss.str(); + } catch (...) { + return "Unknown exception"; + } +} + +} +} diff --git a/libs/fbjni/cxx/lyra/lyra_exceptions.h b/libs/fbjni/cxx/lyra/lyra_exceptions.h new file mode 100644 index 000000000..e04c276af --- /dev/null +++ b/libs/fbjni/cxx/lyra/lyra_exceptions.h @@ -0,0 +1,94 @@ +/** + * Copyright 2004-present, Facebook, Inc. + * + * 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. + */ + +#pragma once + +#include +#include +#include + +#include + +namespace facebook { +namespace lyra { + +namespace detail { + struct ExceptionTraceHolder { + ExceptionTraceHolder(); + // Need some virtual function to make this a polymorphic type. + virtual ~ExceptionTraceHolder(); + ExceptionTraceHolder(const ExceptionTraceHolder&) = delete; + ExceptionTraceHolder(ExceptionTraceHolder&&) = default; + + std::vector stackTrace_; + }; + + template + struct Holder : E, ExceptionTraceHolder { + Holder(E&& e) : E{std::forward(e)}, ExceptionTraceHolder{} {} + }; + template + struct Holder : E { + Holder(E&& e) : E{std::forward(e)} {} + }; +} + +/** + * Retrieves the stack trace of an exception + */ +const std::vector& getExceptionTrace(std::exception_ptr ptr); + +/** + * Throw an exception and store the stack trace. This works like + * std::throw_with_nested in that it will actually throw a type that is + * publicly derived from both E and detail::ExceptionTraceHolder. + */ +template +[[noreturn]] void fbthrow(E&& exception) { + throw detail::Holder::value>{std::forward(exception)}; +} + +/** + * Ensure that a terminate handler that logs traces is installed. + * setLibraryIdentifierFunction should be called first if the stack + * trace should log build ids for libraries. + */ +void ensureRegisteredTerminateHandler(); + +/** + * Helper to convert an exception to a string + */ +std::string toString(std::exception_ptr exceptionPointer); + +/** + * lyra's cxa_throw will delegate to the original cxa throw. That pointer must + * be set before lyra::cxa_throw is called. + * + * One example use would be to statically compile against something that overrides __cxa_throw. + * That would look something like: + * + * [[noreturn]] void __cxa_throw(void* obj, const std::type_info* type, void (*destructor) (void*)) { + * static auto initializer = lyra::original_cxa_throw = lookupOriginalCxaThrow(); + * lyra::cxa_throw(obj, type, destructor); + * } + */ +[[gnu::noreturn]] extern void (*original_cxa_throw)(void*, const std::type_info*, void (*) (void*)); +[[noreturn]] void cxa_throw(void* obj, const std::type_info* type, void (*destructor) (void *)); + +void enableCxaThrowHookBacktraces(bool enable); + +} +} diff --git a/libs/fbjni/java/com/facebook/jni/CppException.java b/libs/fbjni/java/com/facebook/jni/CppException.java new file mode 100644 index 000000000..b84425d2a --- /dev/null +++ b/libs/fbjni/java/com/facebook/jni/CppException.java @@ -0,0 +1,27 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +package com.facebook.jni; + +import com.facebook.jni.annotations.DoNotStrip; + +@DoNotStrip +public class CppException extends RuntimeException { + @DoNotStrip + public CppException(String message) { + super(message); + } +} diff --git a/libs/fbjni/java/com/facebook/jni/CppSystemErrorException.java b/libs/fbjni/java/com/facebook/jni/CppSystemErrorException.java new file mode 100644 index 000000000..a7067a0d4 --- /dev/null +++ b/libs/fbjni/java/com/facebook/jni/CppSystemErrorException.java @@ -0,0 +1,34 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +package com.facebook.jni; + +import com.facebook.jni.annotations.DoNotStrip; + +@DoNotStrip +public class CppSystemErrorException extends CppException { + int errorCode; + + @DoNotStrip + public CppSystemErrorException(String message, int errorCode) { + super(message); + this.errorCode = errorCode; + } + + public int getErrorCode() { + return errorCode; + } +} diff --git a/libs/fbjni/java/com/facebook/jni/DestructorThread.java b/libs/fbjni/java/com/facebook/jni/DestructorThread.java new file mode 100644 index 000000000..233db8d4d --- /dev/null +++ b/libs/fbjni/java/com/facebook/jni/DestructorThread.java @@ -0,0 +1,148 @@ +/** + * Copyright 2004-present, Facebook, Inc. + * + * 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. + */ + +package com.facebook.jni; + +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; +import java.util.concurrent.atomic.AtomicReference; + +/** + * A thread which invokes the "destruct" routine for objects after they have been garbage collected. + * + *

An object which needs to be destructed should create a static subclass of {@link Destructor}. + * Once the referent object is garbage collected, the DestructorThread will callback to the {@link + * Destructor#destruct()} method. + * + *

The underlying thread in DestructorThread starts when the first Destructor is constructed and + * then runs indefinitely. + */ +public class DestructorThread { + + /** + * N.B The Destructor SHOULD NOT refer back to its referent object either explicitly or + * implicitly (for example, as a non-static inner class). This will create a reference cycle where + * the referent object will never be garbage collected. + */ + public abstract static class Destructor extends PhantomReference { + + private Destructor next; + private Destructor previous; + + Destructor(Object referent) { + super(referent, sReferenceQueue); + sDestructorStack.push(this); + } + + private Destructor() { + super(null, sReferenceQueue); + } + + /** Callback which is invoked when the original object has been garbage collected. */ + abstract void destruct(); + } + + /** A list to keep all active Destructors in memory confined to the Destructor thread. */ + private static DestructorList sDestructorList; + /** A thread safe stack where new Destructors are placed before being add to sDestructorList. */ + private static DestructorStack sDestructorStack; + + private static ReferenceQueue sReferenceQueue; + private static Thread sThread; + + static { + sDestructorStack = new DestructorStack(); + sReferenceQueue = new ReferenceQueue(); + sDestructorList = new DestructorList(); + sThread = + new Thread("HybridData DestructorThread") { + @Override + public void run() { + while (true) { + try { + Destructor current = (Destructor) sReferenceQueue.remove(); + current.destruct(); + + // If current is in the sDestructorStack, + // transfer all the Destructors in the stack to the list. + if (current.previous == null) { + sDestructorStack.transferAllToList(); + } + + DestructorList.drop(current); + } catch (InterruptedException e) { + // Continue. This thread should never be terminated. + } + } + } + }; + + sThread.start(); + } + + private static class Terminus extends Destructor { + @Override + void destruct() { + throw new IllegalStateException("Cannot destroy Terminus Destructor."); + } + } + + /** This is a thread safe, lock-free Treiber-like Stack of Destructors. */ + private static class DestructorStack { + private AtomicReference mHead = new AtomicReference<>(); + + public void push(Destructor newHead) { + Destructor oldHead; + do { + oldHead = mHead.get(); + newHead.next = oldHead; + } while (!mHead.compareAndSet(oldHead, newHead)); + } + + public void transferAllToList() { + Destructor current = mHead.getAndSet(null); + while (current != null) { + Destructor next = current.next; + sDestructorList.enqueue(current); + current = next; + } + } + } + + /** A doubly-linked list of Destructors. */ + private static class DestructorList { + private Destructor mHead; + + public DestructorList() { + mHead = new Terminus(); + mHead.next = new Terminus(); + mHead.next.previous = mHead; + } + + public void enqueue(Destructor current) { + current.next = mHead.next; + mHead.next = current; + + current.next.previous = current; + current.previous = mHead; + } + + private static void drop(Destructor current) { + current.next.previous = current.previous; + current.previous.next = current.next; + } + } +} diff --git a/libs/fbjni/java/com/facebook/jni/HybridClassBase.java b/libs/fbjni/java/com/facebook/jni/HybridClassBase.java new file mode 100644 index 000000000..c850dabaf --- /dev/null +++ b/libs/fbjni/java/com/facebook/jni/HybridClassBase.java @@ -0,0 +1,22 @@ +/** + * Copyright 2004-present, Facebook, Inc. + * + * 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. + */ + +package com.facebook.jni; + +import com.facebook.jni.annotations.DoNotStrip; + +@DoNotStrip +public abstract class HybridClassBase extends HybridData {} diff --git a/libs/fbjni/java/com/facebook/jni/HybridData.java b/libs/fbjni/java/com/facebook/jni/HybridData.java new file mode 100644 index 000000000..ae0d64a4c --- /dev/null +++ b/libs/fbjni/java/com/facebook/jni/HybridData.java @@ -0,0 +1,87 @@ +/** + * Copyright 2004-present, Facebook, Inc. + * + * 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. + */ + +package com.facebook.jni; + +import com.facebook.jni.annotations.DoNotStrip; +import com.facebook.soloader.SoLoader; + +/** + * This object holds a native C++ member for hybrid Java/C++ objects. + * + *

NB: THREAD SAFETY + * + *

{@link #resetNative} deletes the corresponding native object synchronously on whatever thread + * the method is called on. Otherwise, deletion will occur on the {@link DestructorThread} thread. + */ +@DoNotStrip +public class HybridData { + + static { + SoLoader.loadLibrary("fbjni"); + } + + @DoNotStrip private Destructor mDestructor = new Destructor(this); + + /** + * To explicitly delete the instance, call resetNative(). If the C++ instance is referenced after + * this is called, a NullPointerException will be thrown. resetNative() may be called multiple + * times safely. Because the {@link DestructorThread} also calls resetNative, the instance will + * not leak if this is not called, but timing of deletion and the thread the C++ dtor is called on + * will be at the whim of the Java GC. If you want to control the thread and timing of the + * destructor, you should call resetNative() explicitly. + */ + public synchronized void resetNative() { + mDestructor.destruct(); + } + + /** + * N.B. Thread safety. If you call isValid from a different thread than {@link #resetNative()} + * then be sure to do so while synchronizing on the hybrid. For example: + * + *


+   * synchronized(hybrid) {
+   *   if (hybrid.isValid) {
+   *     // Do stuff.
+   *   }
+   * }
+   * 
+ */ + public boolean isValid() { + return mDestructor.mNativePointer != 0; + } + + public static class Destructor extends DestructorThread.Destructor { + + // Private C++ instance + @DoNotStrip private long mNativePointer; + + Destructor(Object referent) { + super(referent); + } + + @Override + void destruct() { + // When invoked from the DestructorThread instead of resetNative, + // the DestructorThread has exclusive ownership of the HybridData + // so synchronization is not necessary. + deleteNative(mNativePointer); + mNativePointer = 0; + } + + static native void deleteNative(long pointer); + } +} diff --git a/libs/fbjni/java/com/facebook/jni/IteratorHelper.java b/libs/fbjni/java/com/facebook/jni/IteratorHelper.java new file mode 100644 index 000000000..852f7ec98 --- /dev/null +++ b/libs/fbjni/java/com/facebook/jni/IteratorHelper.java @@ -0,0 +1,58 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ +package com.facebook.jni; + +import com.facebook.jni.annotations.DoNotStrip; +import java.util.Iterator; +import javax.annotation.Nullable; + +/** + * To iterate over an Iterator from C++ requires two calls per entry: hasNext() and next(). This + * helper reduces it to one call and one field get per entry. It does not use a generic argument, + * since in C++, the types will be erased, anyway. This is *not* a {@link java.util.Iterator}. + */ +@DoNotStrip +public class IteratorHelper { + private final Iterator mIterator; + + // This is private, but accessed via JNI. + @DoNotStrip private @Nullable Object mElement; + + @DoNotStrip + public IteratorHelper(Iterator iterator) { + mIterator = iterator; + } + + @DoNotStrip + public IteratorHelper(Iterable iterable) { + mIterator = iterable.iterator(); + } + + /** + * Moves the helper to the next entry in the map, if any. Returns true iff there is an entry to + * read. + */ + @DoNotStrip + boolean hasNext() { + if (mIterator.hasNext()) { + mElement = mIterator.next(); + return true; + } else { + mElement = null; + return false; + } + } +} diff --git a/libs/fbjni/java/com/facebook/jni/MapIteratorHelper.java b/libs/fbjni/java/com/facebook/jni/MapIteratorHelper.java new file mode 100644 index 000000000..342d549fe --- /dev/null +++ b/libs/fbjni/java/com/facebook/jni/MapIteratorHelper.java @@ -0,0 +1,57 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ +package com.facebook.jni; + +import com.facebook.jni.annotations.DoNotStrip; +import java.util.Iterator; +import java.util.Map; +import javax.annotation.Nullable; + +/** + * To iterate over a Map from C++ requires four calls per entry: hasNext(), next(), getKey(), + * getValue(). This helper reduces it to one call and two field gets per entry. It does not use a + * generic argument, since in C++, the types will be erased, anyway. This is *not* a {@link + * java.util.Iterator}. + */ +@DoNotStrip +public class MapIteratorHelper { + @DoNotStrip private final Iterator mIterator; + @DoNotStrip private @Nullable Object mKey; + @DoNotStrip private @Nullable Object mValue; + + @DoNotStrip + public MapIteratorHelper(Map map) { + mIterator = map.entrySet().iterator(); + } + + /** + * Moves the helper to the next entry in the map, if any. Returns true iff there is an entry to + * read. + */ + @DoNotStrip + boolean hasNext() { + if (mIterator.hasNext()) { + Map.Entry entry = mIterator.next(); + mKey = entry.getKey(); + mValue = entry.getValue(); + return true; + } else { + mKey = null; + mValue = null; + return false; + } + } +} diff --git a/libs/fbjni/java/com/facebook/jni/NativeRunnable.java b/libs/fbjni/java/com/facebook/jni/NativeRunnable.java new file mode 100644 index 000000000..a7b2cbf6a --- /dev/null +++ b/libs/fbjni/java/com/facebook/jni/NativeRunnable.java @@ -0,0 +1,31 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ +package com.facebook.jni; + +import com.facebook.jni.annotations.DoNotStrip; + +/** A Runnable that has a native run implementation. */ +@DoNotStrip +public class NativeRunnable implements Runnable { + + private final HybridData mHybridData; + + private NativeRunnable(HybridData hybridData) { + mHybridData = hybridData; + } + + public native void run(); +} diff --git a/libs/fbjni/java/com/facebook/jni/ThreadScopeSupport.java b/libs/fbjni/java/com/facebook/jni/ThreadScopeSupport.java new file mode 100644 index 000000000..be04e4e62 --- /dev/null +++ b/libs/fbjni/java/com/facebook/jni/ThreadScopeSupport.java @@ -0,0 +1,36 @@ +/** + * Copyright 2004-present, Facebook, Inc. + * + * 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. + */ + +package com.facebook.jni; + +import com.facebook.jni.annotations.DoNotStrip; +import com.facebook.soloader.SoLoader; + +@DoNotStrip +public class ThreadScopeSupport { + static { + SoLoader.loadLibrary("fbjni"); + } + + // This is just used for ThreadScope::withClassLoader to have a java function + // in the stack so that jni has access to the correct classloader. + @DoNotStrip + private static void runStdFunction(long ptr) { + runStdFunctionImpl(ptr); + } + + private static native void runStdFunctionImpl(long ptr); +} diff --git a/libs/fbjni/java/com/facebook/jni/UnknownCppException.java b/libs/fbjni/java/com/facebook/jni/UnknownCppException.java new file mode 100644 index 000000000..3a0e70d79 --- /dev/null +++ b/libs/fbjni/java/com/facebook/jni/UnknownCppException.java @@ -0,0 +1,32 @@ +/** + * Copyright 2018-present, Facebook, Inc. + * + * 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. + */ + +package com.facebook.jni; + +import com.facebook.jni.annotations.DoNotStrip; + +@DoNotStrip +public class UnknownCppException extends CppException { + @DoNotStrip + public UnknownCppException() { + super("Unknown"); + } + + @DoNotStrip + public UnknownCppException(String message) { + super(message); + } +} diff --git a/libs/fbjni/java/com/facebook/jni/annotations/DoNotStrip.java b/libs/fbjni/java/com/facebook/jni/annotations/DoNotStrip.java new file mode 100644 index 000000000..7e7facd39 --- /dev/null +++ b/libs/fbjni/java/com/facebook/jni/annotations/DoNotStrip.java @@ -0,0 +1,33 @@ +/** + * Copyright 2004-present, Facebook, Inc. + * + * 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. + */ + +package com.facebook.jni.annotations; + +import static java.lang.annotation.RetentionPolicy.CLASS; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Add this annotation to a class, method, or field to instruct Proguard to not strip it out. + * + * This is useful for methods called via reflection that could appear as unused to Proguard. + */ +@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR }) +@Retention(CLASS) +public @interface DoNotStrip { +} diff --git a/libs/fbjni/src/main/AndroidManifest.xml b/libs/fbjni/src/main/AndroidManifest.xml deleted file mode 100644 index 8e81b59db..000000000 --- a/libs/fbjni/src/main/AndroidManifest.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - diff --git a/libs/fbjni/src/main/cpp/CMakeLists.txt b/libs/fbjni/src/main/cpp/CMakeLists.txt deleted file mode 100644 index 161471866..000000000 --- a/libs/fbjni/src/main/cpp/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2014-present, Facebook, Inc. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. -# - -cmake_minimum_required(VERSION 3.6.0) - -set(CMAKE_VERBOSE_MAKEFILE on) - -add_compile_options( - -fno-omit-frame-pointer - -fexceptions - -Wall - -std=c++11 - -DDISABLE_CPUCAP - -DDISABLE_XPLAT) - -file(GLOB fb_SRC - *.cpp - jni/*.cpp - lyra/*.cpp) - -set(libjnihack_DIR ../../../../jni-hack/) - -add_library(fb SHARED - ${fb_SRC}) - -target_include_directories(fb PRIVATE - include ${libjnihack_DIR}) - -target_link_libraries(fb log) diff --git a/libs/fbjni/src/main/cpp/assert.cpp b/libs/fbjni/src/main/cpp/assert.cpp deleted file mode 100644 index d39c29e45..000000000 --- a/libs/fbjni/src/main/cpp/assert.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include - -#include -#include - -namespace facebook { - -#define ASSERT_BUF_SIZE 4096 -static char sAssertBuf[ASSERT_BUF_SIZE]; -static AssertHandler gAssertHandler; - -void assertInternal(const char* formatstr ...) { - va_list va_args; - va_start(va_args, formatstr); - vsnprintf(sAssertBuf, sizeof(sAssertBuf), formatstr, va_args); - va_end(va_args); - if (gAssertHandler != NULL) { - gAssertHandler(sAssertBuf); - } - FBLOG(LOG_FATAL, "fbassert", "%s", sAssertBuf); - // crash at this specific address so that we can find our crashes easier - *(int*)0xdeadb00c = 0; - // let the compiler know we won't reach the end of the function - __builtin_unreachable(); -} - -void setAssertHandler(AssertHandler assertHandler) { - gAssertHandler = assertHandler; -} - -} // namespace facebook diff --git a/libs/fbjni/src/main/cpp/include/fb/ALog.h b/libs/fbjni/src/main/cpp/include/fb/ALog.h deleted file mode 100644 index 5f231cb7c..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/ALog.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -/** @file ALog.h - * - * Very simple android only logging. Define LOG_TAG to enable the macros. - */ - -#pragma once - -#ifdef __ANDROID__ - -#include - -namespace facebook { -namespace alog { - -template -inline void log(int level, const char* tag, const char* msg, ARGS... args) noexcept { - __android_log_print(level, tag, msg, args...); -} - -template -inline void log(int level, const char* tag, const char* msg) noexcept { - __android_log_write(level, tag, msg); -} - -template -inline void logv(const char* tag, const char* msg, ARGS... args) noexcept { - log(ANDROID_LOG_VERBOSE, tag, msg, args...); -} - -template -inline void logd(const char* tag, const char* msg, ARGS... args) noexcept { - log(ANDROID_LOG_DEBUG, tag, msg, args...); -} - -template -inline void logi(const char* tag, const char* msg, ARGS... args) noexcept { - log(ANDROID_LOG_INFO, tag, msg, args...); -} - -template -inline void logw(const char* tag, const char* msg, ARGS... args) noexcept { - log(ANDROID_LOG_WARN, tag, msg, args...); -} - -template -inline void loge(const char* tag, const char* msg, ARGS... args) noexcept { - log(ANDROID_LOG_ERROR, tag, msg, args...); -} - -template -inline void logf(const char* tag, const char* msg, ARGS... args) noexcept { - log(ANDROID_LOG_FATAL, tag, msg, args...); -} - - -#ifdef LOG_TAG -# define ALOGV(...) ::facebook::alog::logv(LOG_TAG, __VA_ARGS__) -# define ALOGD(...) ::facebook::alog::logd(LOG_TAG, __VA_ARGS__) -# define ALOGI(...) ::facebook::alog::logi(LOG_TAG, __VA_ARGS__) -# define ALOGW(...) ::facebook::alog::logw(LOG_TAG, __VA_ARGS__) -# define ALOGE(...) ::facebook::alog::loge(LOG_TAG, __VA_ARGS__) -# define ALOGF(...) ::facebook::alog::logf(LOG_TAG, __VA_ARGS__) -#endif - -}} - -#else -# define ALOGV(...) ((void)0) -# define ALOGD(...) ((void)0) -# define ALOGI(...) ((void)0) -# define ALOGW(...) ((void)0) -# define ALOGE(...) ((void)0) -# define ALOGF(...) ((void)0) -#endif diff --git a/libs/fbjni/src/main/cpp/include/fb/Countable.h b/libs/fbjni/src/main/cpp/include/fb/Countable.h deleted file mode 100644 index 1fafba36a..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/Countable.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once -#include -#include -#include -#include -#include - -namespace facebook { - -class Countable : public noncopyable, public nonmovable { -public: - // RefPtr expects refcount to start at 0 - Countable() : m_refcount(0) {} - virtual ~Countable() - { - FBASSERT(m_refcount == 0); - } - -private: - void ref() { - ++m_refcount; - } - - void unref() { - if (0 == --m_refcount) { - delete this; - } - } - - bool hasOnlyOneRef() const { - return m_refcount == 1; - } - - template friend class RefPtr; - std::atomic m_refcount; -}; - -} diff --git a/libs/fbjni/src/main/cpp/include/fb/Doxyfile b/libs/fbjni/src/main/cpp/include/fb/Doxyfile deleted file mode 100644 index 8b4df6a7c..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/Doxyfile +++ /dev/null @@ -1,18 +0,0 @@ -PROJECT_NAME = "Facebook JNI" -PROJECT_BRIEF = "Helper library to provide safe and convenient access to JNI with very low overhead" -JAVADOC_AUTOBRIEF = YES -EXTRACT_ALL = YES -RECURSIVE = YES -EXCLUDE = tests Asserts.h Countable.h GlobalReference.h LocalReference.h LocalString.h Registration.h WeakReference.h jni_helpers.h Environment.h -EXCLUDE_PATTERNS = *-inl.h *.cpp -GENERATE_HTML = YES -GENERATE_LATEX = NO -ENABLE_PREPROCESSING = YES -HIDE_UNDOC_MEMBERS = YES -HIDE_SCOPE_NAMES = YES -HIDE_FRIEND_COMPOUNDS = YES -HIDE_UNDOC_CLASSES = YES -SHOW_INCLUDE_FILES = NO -PREDEFINED = LOG_TAG=fbjni -EXAMPLE_PATH = samples -#ENABLED_SECTIONS = INTERNAL diff --git a/libs/fbjni/src/main/cpp/include/fb/ProgramLocation.h b/libs/fbjni/src/main/cpp/include/fb/ProgramLocation.h deleted file mode 100644 index 92b45406f..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/ProgramLocation.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once -#include -#include -#include - -namespace facebook { - -#define FROM_HERE facebook::ProgramLocation(__FUNCTION__, __FILE__, __LINE__) - -class ProgramLocation { -public: - ProgramLocation() : m_functionName("Unspecified"), m_fileName("Unspecified"), m_lineNumber(0) {} - - ProgramLocation(const char* functionName, const char* fileName, int line) : - m_functionName(functionName), - m_fileName(fileName), - m_lineNumber(line) - {} - - const char* functionName() const { return m_functionName; } - const char* fileName() const { return m_fileName; } - int lineNumber() const { return m_lineNumber; } - - std::string asFormattedString() const { - std::stringstream str; - str << "Function " << m_functionName << " in file " << m_fileName << ":" << m_lineNumber; - return str.str(); - } - - bool operator==(const ProgramLocation& other) const { - // Assumes that the strings are static - return (m_functionName == other.m_functionName) && (m_fileName == other.m_fileName) && m_lineNumber == other.m_lineNumber; - } - -private: - const char* m_functionName; - const char* m_fileName; - int m_lineNumber; -}; - -} diff --git a/libs/fbjni/src/main/cpp/include/fb/RefPtr.h b/libs/fbjni/src/main/cpp/include/fb/RefPtr.h deleted file mode 100644 index ee19960fa..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/RefPtr.h +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once -#include -#include - -namespace facebook { - -// Reference counting smart pointer. This is designed to work with the -// Countable class or other implementations in the future. It is designed in a -// way to be both efficient and difficult to misuse. Typical usage is very -// simple once you learn the patterns (and the compiler will help!): -// -// By default, the internal pointer is null. -// RefPtr ref; -// -// Object creation requires explicit construction: -// RefPtr ref = createNew(...); -// -// Or if the constructor is not public: -// RefPtr ref = adoptRef(new Foo(...)); -// -// But you can implicitly create from nullptr: -// RefPtr maybeRef = cond ? ref : nullptr; -// -// Move/Copy Construction/Assignment are straightforward: -// RefPtr ref2 = ref; -// ref = std::move(ref2); -// -// Destruction automatically drops the RefPtr's reference as expected. -// -// Upcasting is implicit but downcasting requires an explicit cast: -// struct Bar : public Foo {}; -// RefPtr barRef = static_cast>(ref); -// ref = barRef; -// -template -class RefPtr { -public: - constexpr RefPtr() : - m_ptr(nullptr) - {} - - // Allow implicit construction from a pointer only from nullptr - constexpr RefPtr(std::nullptr_t ptr) : - m_ptr(nullptr) - {} - - RefPtr(const RefPtr& ref) : - m_ptr(ref.m_ptr) - { - refIfNecessary(m_ptr); - } - - // Only allow implicit upcasts. A downcast will result in a compile error - // unless you use static_cast (which will end up invoking the explicit - // operator below). - template - RefPtr(const RefPtr& ref, typename std::enable_if::value, U>::type* = nullptr) : - m_ptr(ref.get()) - { - refIfNecessary(m_ptr); - } - - RefPtr(RefPtr&& ref) : - m_ptr(nullptr) - { - *this = std::move(ref); - } - - // Only allow implicit upcasts. A downcast will result in a compile error - // unless you use static_cast (which will end up invoking the explicit - // operator below). - template - RefPtr(RefPtr&& ref, typename std::enable_if::value, U>::type* = nullptr) : - m_ptr(nullptr) - { - *this = std::move(ref); - } - - ~RefPtr() { - unrefIfNecessary(m_ptr); - m_ptr = nullptr; - } - - RefPtr& operator=(const RefPtr& ref) { - if (m_ptr != ref.m_ptr) { - unrefIfNecessary(m_ptr); - m_ptr = ref.m_ptr; - refIfNecessary(m_ptr); - } - return *this; - } - - // The STL assumes rvalue references are unique and for simplicity's sake, we - // make the same assumption here, that &ref != this. - RefPtr& operator=(RefPtr&& ref) { - unrefIfNecessary(m_ptr); - m_ptr = ref.m_ptr; - ref.m_ptr = nullptr; - return *this; - } - - template - RefPtr& operator=(RefPtr&& ref) { - unrefIfNecessary(m_ptr); - m_ptr = ref.m_ptr; - ref.m_ptr = nullptr; - return *this; - } - - void reset() { - unrefIfNecessary(m_ptr); - m_ptr = nullptr; - } - - T* get() const { - return m_ptr; - } - - T* operator->() const { - return m_ptr; - } - - T& operator*() const { - return *m_ptr; - } - - template - explicit operator RefPtr () const; - - explicit operator bool() const { - return m_ptr ? true : false; - } - - bool isTheLastRef() const { - FBASSERT(m_ptr); - return m_ptr->hasOnlyOneRef(); - } - - // Creates a strong reference from a raw pointer, assuming that is already - // referenced from some other RefPtr. This should be used sparingly. - static inline RefPtr assumeAlreadyReffed(T* ptr) { - return RefPtr(ptr, ConstructionMode::External); - } - - // Creates a strong reference from a raw pointer, assuming that it points to a - // freshly-created object. See the documentation for RefPtr for usage. - static inline RefPtr adoptRef(T* ptr) { - return RefPtr(ptr, ConstructionMode::Adopted); - } - -private: - enum class ConstructionMode { - Adopted, - External - }; - - RefPtr(T* ptr, ConstructionMode mode) : - m_ptr(ptr) - { - FBASSERTMSGF(ptr, "Got null pointer in %s construction mode", mode == ConstructionMode::Adopted ? "adopted" : "external"); - ptr->ref(); - if (mode == ConstructionMode::Adopted) { - FBASSERT(ptr->hasOnlyOneRef()); - } - } - - static inline void refIfNecessary(T* ptr) { - if (ptr) { - ptr->ref(); - } - } - static inline void unrefIfNecessary(T* ptr) { - if (ptr) { - ptr->unref(); - } - } - - template friend class RefPtr; - - T* m_ptr; -}; - -// Creates a strong reference from a raw pointer, assuming that is already -// referenced from some other RefPtr and that it is non-null. This should be -// used sparingly. -template -static inline RefPtr assumeAlreadyReffed(T* ptr) { - return RefPtr::assumeAlreadyReffed(ptr); -} - -// As above, but tolerant of nullptr. -template -static inline RefPtr assumeAlreadyReffedOrNull(T* ptr) { - return ptr ? RefPtr::assumeAlreadyReffed(ptr) : nullptr; -} - -// Creates a strong reference from a raw pointer, assuming that it points to a -// freshly-created object. See the documentation for RefPtr for usage. -template -static inline RefPtr adoptRef(T* ptr) { - return RefPtr::adoptRef(ptr); -} - -template -static inline RefPtr createNew(Args&&... arguments) { - return RefPtr::adoptRef(new T(std::forward(arguments)...)); -} - -template template -RefPtr::operator RefPtr() const { - static_assert(std::is_base_of::value, "Invalid static cast"); - return assumeAlreadyReffedOrNull(static_cast(m_ptr)); -} - -template -inline bool operator==(const RefPtr& a, const RefPtr& b) { - return a.get() == b.get(); -} - -template -inline bool operator!=(const RefPtr& a, const RefPtr& b) { - return a.get() != b.get(); -} - -template -inline bool operator==(const RefPtr& ref, U* ptr) { - return ref.get() == ptr; -} - -template -inline bool operator!=(const RefPtr& ref, U* ptr) { - return ref.get() != ptr; -} - -template -inline bool operator==(U* ptr, const RefPtr& ref) { - return ref.get() == ptr; -} - -template -inline bool operator!=(U* ptr, const RefPtr& ref) { - return ref.get() != ptr; -} - -template -inline bool operator==(const RefPtr& ref, std::nullptr_t ptr) { - return ref.get() == ptr; -} - -template -inline bool operator!=(const RefPtr& ref, std::nullptr_t ptr) { - return ref.get() != ptr; -} - -template -inline bool operator==(std::nullptr_t ptr, const RefPtr& ref) { - return ref.get() == ptr; -} - -template -inline bool operator!=(std::nullptr_t ptr, const RefPtr& ref) { - return ref.get() != ptr; -} - -} diff --git a/libs/fbjni/src/main/cpp/include/fb/StaticInitialized.h b/libs/fbjni/src/main/cpp/include/fb/StaticInitialized.h deleted file mode 100644 index c5ecc2fed..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/StaticInitialized.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once -#include -#include - -namespace facebook { - -// Class that lets you declare a global but does not add a static constructor -// to the binary. Eventually I'd like to have this auto-initialize in a -// multithreaded environment but for now it's easiest just to use manual -// initialization. -template -class StaticInitialized { -public: - constexpr StaticInitialized() : - m_instance(nullptr) - {} - - template - void initialize(Args&&... arguments) { - FBASSERT(!m_instance); - m_instance = new T(std::forward(arguments)...); - } - - T* operator->() const { - return m_instance; - } -private: - T* m_instance; -}; - -} diff --git a/libs/fbjni/src/main/cpp/include/fb/ThreadLocal.h b/libs/fbjni/src/main/cpp/include/fb/ThreadLocal.h deleted file mode 100644 index 1b868c44f..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/ThreadLocal.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include - -#include - -namespace facebook { - -/////////////////////////////////////////////////////////////////////////////// - -/** - * A thread-local object is a "global" object within a thread. This is useful - * for writing apartment-threaded code, where nothing is actullay shared - * between different threads (hence no locking) but those variables are not - * on stack in local scope. To use it, just do something like this, - * - * ThreadLocal static_object; - * static_object->data_ = ...; - * static_object->doSomething(); - * - * ThreadLocal static_number; - * int value = *static_number; - * - * So, syntax-wise it's similar to pointers. T can be primitive types, and if - * it's a class, there has to be a default constructor. - */ -template -class ThreadLocal { -public: - /** - * Constructor that has to be called from a thread-neutral place. - */ - ThreadLocal() : - m_key(0), - m_cleanup(OnThreadExit) { - initialize(); - } - - /** - * As above but with a custom cleanup function - */ - typedef void (*CleanupFunction)(void* obj); - explicit ThreadLocal(CleanupFunction cleanup) : - m_key(0), - m_cleanup(cleanup) { - FBASSERT(cleanup); - initialize(); - } - - /** - * Access object's member or method through this operator overload. - */ - T *operator->() const { - return get(); - } - - T &operator*() const { - return *get(); - } - - T *get() const { - return (T*)pthread_getspecific(m_key); - } - - T* release() { - T* obj = get(); - pthread_setspecific(m_key, NULL); - return obj; - } - - void reset(T* other = NULL) { - T* old = (T*)pthread_getspecific(m_key); - if (old != other) { - FBASSERT(m_cleanup); - m_cleanup(old); - pthread_setspecific(m_key, other); - } - } - -private: - void initialize() { - int ret = pthread_key_create(&m_key, m_cleanup); - if (ret != 0) { - const char *msg = "(unknown error)"; - switch (ret) { - case EAGAIN: - msg = "PTHREAD_KEYS_MAX (1024) is exceeded"; - break; - case ENOMEM: - msg = "Out-of-memory"; - break; - } - (void) msg; - FBASSERTMSGF(0, "pthread_key_create failed: %d %s", ret, msg); - } - } - - static void OnThreadExit(void *obj) { - if (NULL != obj) { - delete (T*)obj; - } - } - - pthread_key_t m_key; - CleanupFunction m_cleanup; -}; - -} diff --git a/libs/fbjni/src/main/cpp/include/fb/assert.h b/libs/fbjni/src/main/cpp/include/fb/assert.h deleted file mode 100644 index ea0c3f65e..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/assert.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#ifndef FBASSERT_H -#define FBASSERT_H - -#include - -namespace facebook { -#define ENABLE_FBASSERT 1 - -#if ENABLE_FBASSERT -#define FBASSERTMSGF(expr, msg, ...) !(expr) ? facebook::assertInternal("Assert (%s:%d): " msg, __FILE__, __LINE__, ##__VA_ARGS__) : (void) 0 -#else -#define FBASSERTMSGF(expr, msg, ...) -#endif // ENABLE_FBASSERT - -#define FBASSERT(expr) FBASSERTMSGF(expr, "%s", #expr) - -#define FBCRASH(msg, ...) facebook::assertInternal("Fatal error (%s:%d): " msg, __FILE__, __LINE__, ##__VA_ARGS__) -#define FBUNREACHABLE() facebook::assertInternal("This code should be unreachable (%s:%d)", __FILE__, __LINE__) - -FBEXPORT void assertInternal(const char* formatstr, ...) __attribute__((noreturn)); - -// This allows storing the assert message before the current process terminates due to a crash -typedef void (*AssertHandler)(const char* message); -void setAssertHandler(AssertHandler assertHandler); - -} // namespace facebook -#endif // FBASSERT_H diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni.h b/libs/fbjni/src/main/cpp/include/fb/fbjni.h deleted file mode 100644 index 0456d77a3..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/ByteBuffer.h b/libs/fbjni/src/main/cpp/include/fb/fbjni/ByteBuffer.h deleted file mode 100644 index 21d17a27a..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/ByteBuffer.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2016-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include - -#include "CoreClasses.h" -#include "References-forward.h" - -namespace facebook { -namespace jni { - -// JNI's NIO support has some awkward preconditions and error reporting. This -// class provides much more user-friendly access. -class FBEXPORT JByteBuffer : public JavaClass { - public: - static constexpr const char* kJavaDescriptor = "Ljava/nio/ByteBuffer;"; - - static local_ref wrapBytes(uint8_t* data, size_t size); - - bool isDirect() const; - - uint8_t* getDirectBytes() const; - size_t getDirectSize() const; -}; - -}} diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/Context.h b/libs/fbjni/src/main/cpp/include/fb/fbjni/Context.h deleted file mode 100644 index 726a25333..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/Context.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2016-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include "CoreClasses.h" -#include "File.h" - -namespace facebook { -namespace jni { - -class AContext : public JavaClass { - public: - static constexpr const char* kJavaDescriptor = "Landroid/content/Context;"; - - // Define a method that calls into the represented Java class - local_ref getCacheDir() { - static auto method = getClass()->getMethod("getCacheDir"); - return method(self()); - } - - local_ref getFilesDir() { - static auto method = getClass()->getMethod("getFilesDir"); - return method(self()); - } -}; - -} -} diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/File.h b/libs/fbjni/src/main/cpp/include/fb/fbjni/File.h deleted file mode 100644 index 74c752a07..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/File.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2016-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include "CoreClasses.h" - -namespace facebook { -namespace jni { - -class JFile : public JavaClass { - public: - static constexpr const char* kJavaDescriptor = "Ljava/io/File;"; - - // Define a method that calls into the represented Java class - std::string getAbsolutePath() { - static auto method = getClass()->getMethod("getAbsolutePath"); - return method(self())->toStdString(); - } - -}; - -} -} diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/JThread.h b/libs/fbjni/src/main/cpp/include/fb/fbjni/JThread.h deleted file mode 100644 index 1bb61199f..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/JThread.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2016-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include "CoreClasses.h" -#include "NativeRunnable.h" - -namespace facebook { -namespace jni { - -class JThread : public JavaClass { - public: - static constexpr const char* kJavaDescriptor = "Ljava/lang/Thread;"; - - void start() { - static auto method = javaClassStatic()->getMethod("start"); - method(self()); - } - - void join() { - static auto method = javaClassStatic()->getMethod("join"); - method(self()); - } - - static local_ref create(std::function&& runnable) { - auto jrunnable = JNativeRunnable::newObjectCxxArgs(std::move(runnable)); - return newInstance(static_ref_cast(jrunnable)); - } -}; - -} -} diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/JThrowable.h b/libs/fbjni/src/main/cpp/include/fb/fbjni/JThrowable.h deleted file mode 100644 index 85a12e817..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/JThrowable.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -#pragma once -#include "CoreClasses.h" - -struct JThrowable : public facebook::jni::JavaClass { - constexpr static auto kJavaDescriptor = "Ljava/lang/Throwable;"; - - std::string getStackTrace() const; -}; diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/Meta-forward.h b/libs/fbjni/src/main/cpp/include/fb/fbjni/Meta-forward.h deleted file mode 100644 index 60dfee44d..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/Meta-forward.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -namespace facebook { -namespace jni { - -template -class JMethod; -template -class JStaticMethod; -template -class JNonvirtualMethod; -template -struct JConstructor; -template -class JField; -template -class JStaticField; - -/// Type traits for Java types (currently providing Java type descriptors) -template -struct jtype_traits; - -/// Type traits for Java methods (currently providing Java type descriptors) -template -struct jmethod_traits; - -}} diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/ReferenceAllocators.h b/libs/fbjni/src/main/cpp/include/fb/fbjni/ReferenceAllocators.h deleted file mode 100644 index a971263ad..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/ReferenceAllocators.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -/** - * @file ReferenceAllocators.h - * - * Reference allocators are used to create and delete various classes of JNI references (local, - * global, and weak global). - */ - -#pragma once - -#include - -#include "Common.h" - -namespace facebook { namespace jni { - -/// Allocator that handles local references -class FBEXPORT LocalReferenceAllocator { - public: - jobject newReference(jobject original) const; - void deleteReference(jobject reference) const noexcept; - bool verifyReference(jobject reference) const noexcept; -}; - -/// Allocator that handles global references -class FBEXPORT GlobalReferenceAllocator { - public: - jobject newReference(jobject original) const; - void deleteReference(jobject reference) const noexcept; - bool verifyReference(jobject reference) const noexcept; -}; - -/// Allocator that handles weak global references -class FBEXPORT WeakGlobalReferenceAllocator { - public: - jobject newReference(jobject original) const; - void deleteReference(jobject reference) const noexcept; - bool verifyReference(jobject reference) const noexcept; -}; - -/// @cond INTERNAL -namespace internal { - -/** - * @return true iff env->GetObjectRefType is expected to work properly. - */ -FBEXPORT bool doesGetObjectRefTypeWork(); - -} -/// @endcond - -}} - -#include "ReferenceAllocators-inl.h" diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/Registration-inl.h b/libs/fbjni/src/main/cpp/include/fb/fbjni/Registration-inl.h deleted file mode 100644 index e28174736..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/Registration-inl.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include "Exceptions.h" -#include "Hybrid.h" - -namespace facebook { -namespace jni { - -namespace detail { - -#ifdef __i386__ -// X86 ABI forces 16 byte stack allignment on calls. Unfortunately -// sometimes Dalvik chooses not to obey the ABI: -// - https://code.google.com/p/android/issues/detail?id=61012 -// - https://android.googlesource.com/platform/ndk/+/81696d2%5E!/ -// Therefore, we tell the compiler to re-align the stack on entry -// to our JNI functions. -#define JNI_ENTRY_POINT __attribute__((force_align_arg_pointer)) -#else -#define JNI_ENTRY_POINT -#endif - -// registration wrapper for legacy JNI-style functions - -template -inline NativeMethodWrapper* exceptionWrapJNIMethod(void (*)(JNIEnv*, C, Args... args)) { - struct funcWrapper { - JNI_ENTRY_POINT static void call(JNIEnv* env, jobject obj, Args... args) { - // Note that if func was declared noexcept, then both gcc and clang are smart - // enough to elide the try/catch. - try { - (*func)(env, static_cast(obj), args...); - } catch (...) { - translatePendingCppExceptionToJavaException(); - } - } - }; - - // This intentionally erases the real type; JNI will do it anyway - return reinterpret_cast(&(funcWrapper::call)); -} - -template -inline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(JNIEnv*, C, Args... args)) { - struct funcWrapper { - JNI_ENTRY_POINT static R call(JNIEnv* env, jobject obj, Args... args) { - try { - return (*func)(env, static_cast>(obj), args...); - } catch (...) { - translatePendingCppExceptionToJavaException(); - return R{}; - } - } - }; - - // This intentionally erases the real type; JNI will do it anyway - return reinterpret_cast(&(funcWrapper::call)); -} - -// registration wrappers for functions, with autoconversion of arguments. - -template -inline NativeMethodWrapper* exceptionWrapJNIMethod(void (*)(alias_ref, Args... args)) { - struct funcWrapper { - JNI_ENTRY_POINT static void call(JNIEnv*, jobject obj, - typename Convert::type>::jniType... args) { - try { - (*func)(static_cast>(obj), Convert::type>::fromJni(args)...); - } catch (...) { - translatePendingCppExceptionToJavaException(); - } - } - }; - - // This intentionally erases the real type; JNI will do it anyway - return reinterpret_cast(&(funcWrapper::call)); -} - -template -inline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(alias_ref, Args... args)) { - struct funcWrapper { - - JNI_ENTRY_POINT static typename Convert::type>::jniType call(JNIEnv*, jobject obj, - typename Convert::type>::jniType... args) { - try { - return Convert::type>::toJniRet( - (*func)(static_cast>(obj), Convert::type>::fromJni(args)...)); - } catch (...) { - using jniRet = typename Convert::type>::jniType; - translatePendingCppExceptionToJavaException(); - return jniRet{}; - } - } - }; - - // This intentionally erases the real type; JNI will do it anyway - return reinterpret_cast(&(funcWrapper::call)); -} - -// registration wrappers for non-static methods, with autoconvertion of arguments. - -template -inline NativeMethodWrapper* exceptionWrapJNIMethod(void (C::*method0)(Args... args)) { - struct funcWrapper { - JNI_ENTRY_POINT static void call(JNIEnv* env, jobject obj, - typename Convert::type>::jniType... args) { - try { - try { - auto aref = wrap_alias(static_cast(obj)); - // This is usually a noop, but if the hybrid object is a - // base class of other classes which register JNI methods, - // this will get the right type for the registered method. - auto cobj = static_cast(facebook::jni::cthis(aref)); - (cobj->*method)(Convert::type>::fromJni(args)...); - } catch (const std::exception& ex) { - C::mapException(ex); - throw; - } - } catch (...) { - translatePendingCppExceptionToJavaException(); - } - } - }; - - // This intentionally erases the real type; JNI will do it anyway - return reinterpret_cast(&(funcWrapper::call)); -} - -template -inline NativeMethodWrapper* exceptionWrapJNIMethod(R (C::*method0)(Args... args)) { - struct funcWrapper { - - JNI_ENTRY_POINT static typename Convert::type>::jniType call(JNIEnv* env, jobject obj, - typename Convert::type>::jniType... args) { - try { - try { - auto aref = wrap_alias(static_cast(obj)); - // This is usually a noop, but if the hybrid object is a - // base class of other classes which register JNI methods, - // this will get the right type for the registered method. - auto cobj = static_cast(facebook::jni::cthis(aref)); - return Convert::type>::toJniRet( - (cobj->*method)(Convert::type>::fromJni(args)...)); - } catch (const std::exception& ex) { - C::mapException(ex); - throw; - } - } catch (...) { - using jniRet = typename Convert::type>::jniType; - translatePendingCppExceptionToJavaException(); - return jniRet{}; - } - } - }; - - // This intentionally erases the real type; JNI will do it anyway - return reinterpret_cast(&(funcWrapper::call)); -} - -template -inline std::string makeDescriptor(R (*)(JNIEnv*, C, Args... args)) { - return jmethod_traits::descriptor(); -} - -template -inline std::string makeDescriptor(R (*)(alias_ref, Args... args)) { - return jmethod_traits_from_cxx::descriptor(); -} - -template -inline std::string makeDescriptor(R (C::*)(Args... args)) { - return jmethod_traits_from_cxx::descriptor(); -} - -} - -}} diff --git a/libs/fbjni/src/main/cpp/include/fb/log.h b/libs/fbjni/src/main/cpp/include/fb/log.h deleted file mode 100644 index e26e716bf..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/log.h +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright (C) 2005 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. - */ - -/* - * FB Wrapper for logging functions. - * - * The android logging API uses the macro "LOG()" for its logic, which means - * that it conflicts with random other places that use LOG for their own - * purposes and doesn't work right half the places you include it - * - * FBLOG uses exactly the same semantics (FBLOGD for debug etc) but because of - * the FB prefix it's strictly better. FBLOGV also gets stripped out based on - * whether NDEBUG is set, but can be overridden by FBLOG_NDEBUG - * - * Most of the rest is a copy of with minor changes. - */ - -// -// C/C++ logging functions. See the logging documentation for API details. -// -// We'd like these to be available from C code (in case we import some from -// somewhere), so this has a C interface. -// -// The output will be correct when the log file is shared between multiple -// threads and/or multiple processes so long as the operating system -// supports O_APPEND. These calls have mutex-protected data structures -// and so are NOT reentrant. Do not use LOG in a signal handler. -// -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef ANDROID -#include -#else -// These declarations are needed for our internal use even on non-Android -// builds. -// (they are borrowed from ) - -/* - * Android log priority values, in ascending priority order. - */ -typedef enum android_LogPriority { - ANDROID_LOG_UNKNOWN = 0, - ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */ - ANDROID_LOG_VERBOSE, - ANDROID_LOG_DEBUG, - ANDROID_LOG_INFO, - ANDROID_LOG_WARN, - ANDROID_LOG_ERROR, - ANDROID_LOG_FATAL, - ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */ -} android_LogPriority; - -/* - * Send a simple string to the log. - */ -int __android_log_write(int prio, const char *tag, const char *text); - -/* - * Send a formatted string to the log, used like printf(fmt,...) - */ -int __android_log_print(int prio, const char *tag, const char *fmt, ...) -#if defined(__GNUC__) - __attribute__((format(printf, 3, 4))) -#endif - ; - -#endif - -// --------------------------------------------------------------------- - -/* - * Normally we strip FBLOGV (VERBOSE messages) from release builds. - * You can modify this (for example with "#define FBLOG_NDEBUG 0" - * at the top of your source file) to change that behavior. - */ -#ifndef FBLOG_NDEBUG -#ifdef NDEBUG -#define FBLOG_NDEBUG 1 -#else -#define FBLOG_NDEBUG 0 -#endif -#endif - -/* - * This is the local tag used for the following simplified - * logging macros. You can change this preprocessor definition - * before using the other macros to change the tag. - */ -#ifndef LOG_TAG -#define LOG_TAG NULL -#endif - -// --------------------------------------------------------------------- - -/* - * Simplified macro to send a verbose log message using the current LOG_TAG. - */ -#ifndef FBLOGV -#if FBLOG_NDEBUG -#define FBLOGV(...) ((void)0) -#else -#define FBLOGV(...) ((void)FBLOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) -#endif -#endif - -#define CONDITION(cond) (__builtin_expect((cond) != 0, 0)) - -#ifndef FBLOGV_IF -#if FBLOG_NDEBUG -#define FBLOGV_IF(cond, ...) ((void)0) -#else -#define FBLOGV_IF(cond, ...) \ - ((CONDITION(cond)) ? ((void)FBLOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ - : (void)0) -#endif -#endif - -/* - * Simplified macro to send a debug log message using the current LOG_TAG. - */ -#ifndef FBLOGD -#define FBLOGD(...) ((void)FBLOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef FBLOGD_IF -#define FBLOGD_IF(cond, ...) \ - ((CONDITION(cond)) ? ((void)FBLOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) : (void)0) -#endif - -/* - * Simplified macro to send an info log message using the current LOG_TAG. - */ -#ifndef FBLOGI -#define FBLOGI(...) ((void)FBLOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef FBLOGI_IF -#define FBLOGI_IF(cond, ...) \ - ((CONDITION(cond)) ? ((void)FBLOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) : (void)0) -#endif - -/* - * Simplified macro to send a warning log message using the current LOG_TAG. - */ -#ifndef FBLOGW -#define FBLOGW(...) ((void)FBLOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef FBLOGW_IF -#define FBLOGW_IF(cond, ...) \ - ((CONDITION(cond)) ? ((void)FBLOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) : (void)0) -#endif - -/* - * Simplified macro to send an error log message using the current LOG_TAG. - */ -#ifndef FBLOGE -#define FBLOGE(...) ((void)FBLOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef FBLOGE_IF -#define FBLOGE_IF(cond, ...) \ - ((CONDITION(cond)) ? ((void)FBLOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) : (void)0) -#endif - -// --------------------------------------------------------------------- - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * verbose priority. - */ -#ifndef IF_FBLOGV -#if FBLOG_NDEBUG -#define IF_FBLOGV() if (false) -#else -#define IF_FBLOGV() IF_FBLOG(LOG_VERBOSE, LOG_TAG) -#endif -#endif - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * debug priority. - */ -#ifndef IF_FBLOGD -#define IF_FBLOGD() IF_FBLOG(LOG_DEBUG, LOG_TAG) -#endif - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * info priority. - */ -#ifndef IF_FBLOGI -#define IF_FBLOGI() IF_FBLOG(LOG_INFO, LOG_TAG) -#endif - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * warn priority. - */ -#ifndef IF_FBLOGW -#define IF_FBLOGW() IF_FBLOG(LOG_WARN, LOG_TAG) -#endif - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * error priority. - */ -#ifndef IF_FBLOGE -#define IF_FBLOGE() IF_FBLOG(LOG_ERROR, LOG_TAG) -#endif - -// --------------------------------------------------------------------- - -/* - * Log a fatal error. If the given condition fails, this stops program - * execution like a normal assertion, but also generating the given message. - * It is NOT stripped from release builds. Note that the condition test - * is -inverted- from the normal assert() semantics. - */ -#define FBLOG_ALWAYS_FATAL_IF(cond, ...) \ - ((CONDITION(cond)) ? ((void)fb_printAssert(#cond, LOG_TAG, __VA_ARGS__)) \ - : (void)0) - -#define FBLOG_ALWAYS_FATAL(...) \ - (((void)fb_printAssert(NULL, LOG_TAG, __VA_ARGS__))) - -/* - * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that - * are stripped out of release builds. - */ -#if FBLOG_NDEBUG - -#define FBLOG_FATAL_IF(cond, ...) ((void)0) -#define FBLOG_FATAL(...) ((void)0) - -#else - -#define FBLOG_FATAL_IF(cond, ...) FBLOG_ALWAYS_FATAL_IF(cond, __VA_ARGS__) -#define FBLOG_FATAL(...) FBLOG_ALWAYS_FATAL(__VA_ARGS__) - -#endif - -/* - * Assertion that generates a log message when the assertion fails. - * Stripped out of release builds. Uses the current LOG_TAG. - */ -#define FBLOG_ASSERT(cond, ...) FBLOG_FATAL_IF(!(cond), __VA_ARGS__) -//#define LOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond) - -// --------------------------------------------------------------------- - -/* - * Basic log message macro. - * - * Example: - * FBLOG(LOG_WARN, NULL, "Failed with error %d", errno); - * - * The second argument may be NULL or "" to indicate the "global" tag. - */ -#ifndef FBLOG -#define FBLOG(priority, tag, ...) \ - FBLOG_PRI(ANDROID_##priority, tag, __VA_ARGS__) -#endif - -#ifndef FBLOG_BY_DELIMS -#define FBLOG_BY_DELIMS(priority, tag, delims, msg, ...) \ - logPrintByDelims(ANDROID_##priority, tag, delims, msg, ##__VA_ARGS__) -#endif - -/* - * Log macro that allows you to specify a number for the priority. - */ -#ifndef FBLOG_PRI -#define FBLOG_PRI(priority, tag, ...) fb_printLog(priority, tag, __VA_ARGS__) -#endif - -/* - * Log macro that allows you to pass in a varargs ("args" is a va_list). - */ -#ifndef FBLOG_PRI_VA -#define FBLOG_PRI_VA(priority, tag, fmt, args) \ - fb_vprintLog(priority, NULL, tag, fmt, args) -#endif - -/* - * Conditional given a desired logging priority and tag. - */ -#ifndef IF_FBLOG -#define IF_FBLOG(priority, tag) if (fb_testLog(ANDROID_##priority, tag)) -#endif - -typedef void (*LogHandler)(int priority, const char* tag, const char* message); -FBEXPORT void setLogHandler(LogHandler logHandler); - -/* - * =========================================================================== - * - * The stuff in the rest of this file should not be used directly. - */ -FBEXPORT int fb_printLog(int prio, const char* tag, const char* fmt, ...) -#if defined(__GNUC__) - __attribute__((format(printf, 3, 4))) -#endif - ; - -#define fb_vprintLog(prio, cond, tag, fmt...) \ - __android_log_vprint(prio, tag, fmt) - -#define fb_printAssert(cond, tag, fmt...) __android_log_assert(cond, tag, fmt) - -#define fb_writeLog(prio, tag, text) __android_log_write(prio, tag, text) - -#define fb_bWriteLog(tag, payload, len) __android_log_bwrite(tag, payload, len) -#define fb_btWriteLog(tag, type, payload, len) \ - __android_log_btwrite(tag, type, payload, len) - -#define fb_testLog(prio, tag) (1) - -/* - * FB extensions - */ -void logPrintByDelims(int priority, const char* tag, const char* delims, - const char* msg, ...); - -#ifdef __cplusplus -} -#endif diff --git a/libs/fbjni/src/main/cpp/include/fb/noncopyable.h b/libs/fbjni/src/main/cpp/include/fb/noncopyable.h deleted file mode 100644 index 5dbc03126..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/noncopyable.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -namespace facebook { - -struct noncopyable { - noncopyable(const noncopyable&) = delete; - noncopyable& operator=(const noncopyable&) = delete; -protected: - noncopyable() = default; -}; - -} diff --git a/libs/fbjni/src/main/cpp/include/fb/nonmovable.h b/libs/fbjni/src/main/cpp/include/fb/nonmovable.h deleted file mode 100644 index 41152f5d1..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/nonmovable.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -namespace facebook { - -struct nonmovable { - nonmovable(nonmovable&&) = delete; - nonmovable& operator=(nonmovable&&) = delete; -protected: - nonmovable() = default; -}; - -} diff --git a/libs/fbjni/src/main/cpp/include/fb/visibility.h b/libs/fbjni/src/main/cpp/include/fb/visibility.h deleted file mode 100644 index 6c14b50c1..000000000 --- a/libs/fbjni/src/main/cpp/include/fb/visibility.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#define FBEXPORT __attribute__((visibility("default"))) diff --git a/libs/fbjni/src/main/cpp/include/jni/Countable.h b/libs/fbjni/src/main/cpp/include/jni/Countable.h deleted file mode 100644 index ae59441ba..000000000 --- a/libs/fbjni/src/main/cpp/include/jni/Countable.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include - -#include -#include -#include - -namespace facebook { -namespace jni { - -FBEXPORT const RefPtr& countableFromJava(JNIEnv* env, jobject obj); - -template RefPtr extractRefPtr(JNIEnv* env, jobject obj) { - return static_cast>(countableFromJava(env, obj)); -} - -template RefPtr extractPossiblyNullRefPtr(JNIEnv* env, jobject obj) { - return obj ? extractRefPtr(env, obj) : nullptr; -} - -FBEXPORT void setCountableForJava(JNIEnv* env, jobject obj, RefPtr&& countable); - -void CountableOnLoad(JNIEnv* env); - -} } - diff --git a/libs/fbjni/src/main/cpp/include/jni/GlobalReference.h b/libs/fbjni/src/main/cpp/include/jni/GlobalReference.h deleted file mode 100644 index 20c275e2d..000000000 --- a/libs/fbjni/src/main/cpp/include/jni/GlobalReference.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include - -#include - -#include - -namespace facebook { namespace jni { - -template -class GlobalReference { - static_assert(std::is_convertible::value, - "GlobalReference instantiated with type that is not " - "convertible to jobject"); - - public: - explicit GlobalReference(T globalReference) : - reference_(globalReference? Environment::current()->NewGlobalRef(globalReference) : nullptr) { - } - - ~GlobalReference() { - reset(); - } - - GlobalReference() : - reference_(nullptr) { - } - - // enable move constructor and assignment - GlobalReference(GlobalReference&& rhs) : - reference_(std::move(rhs.reference_)) { - rhs.reference_ = nullptr; - } - - GlobalReference& operator=(GlobalReference&& rhs) { - if (this != &rhs) { - reset(); - reference_ = std::move(rhs.reference_); - rhs.reference_ = nullptr; - } - return *this; - } - - GlobalReference(const GlobalReference& rhs) : - reference_{} { - reset(rhs.get()); - } - - GlobalReference& operator=(const GlobalReference& rhs) { - if (this == &rhs) { - return *this; - } - reset(rhs.get()); - return *this; - } - - explicit operator bool() const { - return (reference_ != nullptr); - } - - T get() const { - return reinterpret_cast(reference_); - } - - void reset(T globalReference = nullptr) { - if (reference_) { - Environment::current()->DeleteGlobalRef(reference_); - } - if (globalReference) { - reference_ = Environment::current()->NewGlobalRef(globalReference); - } else { - reference_ = nullptr; - } - } - - private: - jobject reference_; -}; - -}} diff --git a/libs/fbjni/src/main/cpp/include/jni/LocalReference.h b/libs/fbjni/src/main/cpp/include/jni/LocalReference.h deleted file mode 100644 index 531f26ef8..000000000 --- a/libs/fbjni/src/main/cpp/include/jni/LocalReference.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include - -#include - -#include - -namespace facebook { -namespace jni { - -template -struct LocalReferenceDeleter { - static_assert(std::is_convertible::value, - "LocalReferenceDeleter instantiated with type that is not convertible to jobject"); - void operator()(T localReference) { - if (localReference != nullptr) { - Environment::current()->DeleteLocalRef(localReference); - } - } - }; - -template -using LocalReference = - std::unique_ptr::type, LocalReferenceDeleter>; - -} } diff --git a/libs/fbjni/src/main/cpp/include/jni/Registration.h b/libs/fbjni/src/main/cpp/include/jni/Registration.h deleted file mode 100644 index 8b91cba35..000000000 --- a/libs/fbjni/src/main/cpp/include/jni/Registration.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once -#include -#include -#include - -namespace facebook { -namespace jni { - -static inline void registerNatives(JNIEnv* env, jclass cls, std::initializer_list methods) { - auto result = env->RegisterNatives(cls, methods.begin(), methods.size()); - FBASSERT(result == 0); -} - -static inline void registerNatives(JNIEnv* env, const char* cls, std::initializer_list list) { - registerNatives(env, env->FindClass(cls), list); -} - -} } diff --git a/libs/fbjni/src/main/cpp/include/jni/WeakReference.h b/libs/fbjni/src/main/cpp/include/jni/WeakReference.h deleted file mode 100644 index 898f91e9e..000000000 --- a/libs/fbjni/src/main/cpp/include/jni/WeakReference.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once -#include -#include -#include -#include -#include - - -namespace facebook { -namespace jni { - -class FBEXPORT WeakReference : public Countable { -public: - typedef RefPtr Ptr; - WeakReference(jobject strongRef); - ~WeakReference(); - jweak weakRef() { - return m_weakReference; - } - -private: - jweak m_weakReference; -}; - -// This class is intended to take a weak reference and turn it into a strong -// local reference. Consequently, it should only be allocated on the stack. -class FBEXPORT ResolvedWeakReference : public noncopyable { -public: - ResolvedWeakReference(jobject weakRef); - ResolvedWeakReference(const RefPtr& weakRef); - ~ResolvedWeakReference(); - - operator jobject () { - return m_strongReference; - } - - explicit operator bool () { - return m_strongReference != nullptr; - } - -private: - jobject m_strongReference; -}; - -} } - diff --git a/libs/fbjni/src/main/cpp/include/jni/jni_helpers.h b/libs/fbjni/src/main/cpp/include/jni/jni_helpers.h deleted file mode 100644 index 93912f4a0..000000000 --- a/libs/fbjni/src/main/cpp/include/jni/jni_helpers.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include - -#include - -namespace facebook { - -/** - * Instructs the JNI environment to throw an exception. - * - * @param pEnv JNI environment - * @param szClassName class name to throw - * @param szFmt sprintf-style format string - * @param ... sprintf-style args - * @return 0 on success; a negative value on failure - */ -FBEXPORT jint throwException(JNIEnv* pEnv, const char* szClassName, const char* szFmt, va_list va_args); - -/** - * Instructs the JNI environment to throw a NoClassDefFoundError. - * - * @param pEnv JNI environment - * @param szFmt sprintf-style format string - * @param ... sprintf-style args - * @return 0 on success; a negative value on failure - */ -FBEXPORT jint throwNoClassDefError(JNIEnv* pEnv, const char* szFmt, ...); - -/** - * Instructs the JNI environment to throw a RuntimeException. - * - * @param pEnv JNI environment - * @param szFmt sprintf-style format string - * @param ... sprintf-style args - * @return 0 on success; a negative value on failure - */ -FBEXPORT jint throwRuntimeException(JNIEnv* pEnv, const char* szFmt, ...); - -/** - * Instructs the JNI environment to throw a IllegalArgumentException. - * - * @param pEnv JNI environment - * @param szFmt sprintf-style format string - * @param ... sprintf-style args - * @return 0 on success; a negative value on failure - */ -FBEXPORT jint throwIllegalArgumentException(JNIEnv* pEnv, const char* szFmt, ...); - -/** - * Instructs the JNI environment to throw a IllegalStateException. - * - * @param pEnv JNI environment - * @param szFmt sprintf-style format string - * @param ... sprintf-style args - * @return 0 on success; a negative value on failure - */ -FBEXPORT jint throwIllegalStateException(JNIEnv* pEnv, const char* szFmt, ...); - -/** - * Instructs the JNI environment to throw an IOException. - * - * @param pEnv JNI environment - * @param szFmt sprintf-style format string - * @param ... sprintf-style args - * @return 0 on success; a negative value on failure - */ -FBEXPORT jint throwIOException(JNIEnv* pEnv, const char* szFmt, ...); - -/** - * Instructs the JNI environment to throw an AssertionError. - * - * @param pEnv JNI environment - * @param szFmt sprintf-style format string - * @param ... sprintf-style args - * @return 0 on success; a negative value on failure - */ -FBEXPORT jint throwAssertionError(JNIEnv* pEnv, const char* szFmt, ...); - -/** - * Instructs the JNI environment to throw an OutOfMemoryError. - * - * @param pEnv JNI environment - * @param szFmt sprintf-style format string - * @param ... sprintf-style args - * @return 0 on success; a negative value on failure - */ -FBEXPORT jint throwOutOfMemoryError(JNIEnv* pEnv, const char* szFmt, ...); - -/** - * Finds the specified class. If it's not found, instructs the JNI environment to throw an - * exception. - * - * @param pEnv JNI environment - * @param szClassName the classname to find in JNI format (e.g. "java/lang/String") - * @return the class or NULL if not found (in which case a pending exception will be queued). This - * returns a global reference (JNIEnv::NewGlobalRef). - */ -FBEXPORT jclass findClassOrThrow(JNIEnv *pEnv, const char* szClassName); - -/** - * Finds the specified field of the specified class. If it's not found, instructs the JNI - * environment to throw an exception. - * - * @param pEnv JNI environment - * @param clazz the class to lookup the field in - * @param szFieldName the name of the field to find - * @param szSig the signature of the field - * @return the field or NULL if not found (in which case a pending exception will be queued) - */ -FBEXPORT jfieldID getFieldIdOrThrow(JNIEnv* pEnv, jclass clazz, const char* szFieldName, const char* szSig); - -/** - * Finds the specified method of the specified class. If it's not found, instructs the JNI - * environment to throw an exception. - * - * @param pEnv JNI environment - * @param clazz the class to lookup the method in - * @param szMethodName the name of the method to find - * @param szSig the signature of the method - * @return the method or NULL if not found (in which case a pending exception will be queued) - */ -FBEXPORT jmethodID getMethodIdOrThrow( - JNIEnv* pEnv, - jclass clazz, - const char* szMethodName, - const char* szSig); - -} // namespace facebook - diff --git a/libs/fbjni/src/main/cpp/jni/Countable.cpp b/libs/fbjni/src/main/cpp/jni/Countable.cpp deleted file mode 100644 index ee958bf57..000000000 --- a/libs/fbjni/src/main/cpp/jni/Countable.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include -#include - -namespace facebook { -namespace jni { - -static jfieldID gCountableNativePtr; - -static RefPtr* rawCountableFromJava(JNIEnv* env, jobject obj) { - FBASSERT(obj); - return reinterpret_cast*>(env->GetLongField(obj, gCountableNativePtr)); -} - -const RefPtr& countableFromJava(JNIEnv* env, jobject obj) { - FBASSERT(obj); - return *rawCountableFromJava(env, obj); -} - -void setCountableForJava(JNIEnv* env, jobject obj, RefPtr&& countable) { - int oldValue = env->GetLongField(obj, gCountableNativePtr); - FBASSERTMSGF(oldValue == 0, "Cannot reinitialize object; expected nullptr, got %x", oldValue); - - FBASSERT(countable); - uintptr_t fieldValue = (uintptr_t) new RefPtr(std::move(countable)); - env->SetLongField(obj, gCountableNativePtr, fieldValue); -} - -/** - * NB: THREAD SAFETY (this comment also exists at Countable.java) - * - * This method deletes the corresponding native object on whatever thread the method is called - * on. In the common case when this is called by Countable#finalize(), this will be called on the - * system finalizer thread. If you manually call dispose on the Java object, the native object - * will be deleted synchronously on that thread. - */ -void dispose(JNIEnv* env, jobject obj) { - // Grab the pointer - RefPtr* countable = rawCountableFromJava(env, obj); - if (!countable) { - // That was easy. - return; - } - - // Clear out the old value to avoid double-frees - env->SetLongField(obj, gCountableNativePtr, 0); - - delete countable; -} - -void CountableOnLoad(JNIEnv* env) { - jclass countable = env->FindClass("com/facebook/jni/Countable"); - gCountableNativePtr = env->GetFieldID(countable, "mInstance", "J"); - registerNatives(env, countable, { - { "dispose", "()V", (void*) dispose }, - }); -} - -} } diff --git a/libs/fbjni/src/main/cpp/jni/Environment.cpp b/libs/fbjni/src/main/cpp/jni/Environment.cpp deleted file mode 100644 index 2d0d7de43..000000000 --- a/libs/fbjni/src/main/cpp/jni/Environment.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace facebook { -namespace jni { - -namespace { -StaticInitialized> g_env; -JavaVM* g_vm = nullptr; - -struct JThreadScopeSupport : JavaClass { - static auto constexpr kJavaDescriptor = "Lcom/facebook/jni/ThreadScopeSupport;"; - - // These reinterpret_casts are a totally dangerous pattern. Don't use them. Use HybridData instead. - static void runStdFunction(std::function&& func) { - static auto method = javaClassStatic()->getStaticMethod("runStdFunction"); - method(javaClassStatic(), reinterpret_cast(&func)); - } - - static void runStdFunctionImpl(alias_ref, jlong ptr) { - (*reinterpret_cast*>(ptr))(); - } - - static void OnLoad() { - // We need the javaClassStatic so that the class lookup is cached and that - // runStdFunction can be called from a ThreadScope-attached thread. - javaClassStatic()->registerNatives({ - makeNativeMethod("runStdFunctionImpl", runStdFunctionImpl), - }); - } -}; -} - -/* static */ -JNIEnv* Environment::current() { - JNIEnv* env = g_env->get(); - if ((env == nullptr) && (g_vm != nullptr)) { - if (g_vm->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_OK) { - FBLOGE("Error retrieving JNI Environment, thread is probably not attached to JVM"); - // TODO(cjhopman): This should throw an exception. - env = nullptr; - } else { - g_env->reset(env); - } - } - return env; -} - -/* static */ -void Environment::detachCurrentThread() { - auto env = g_env->get(); - if (env) { - FBASSERT(g_vm); - g_vm->DetachCurrentThread(); - g_env->reset(); - } -} - -struct EnvironmentInitializer { - EnvironmentInitializer(JavaVM* vm) { - FBASSERT(!g_vm); - FBASSERT(vm); - g_vm = vm; - g_env.initialize([] (void*) {}); - } -}; - -/* static */ -void Environment::initialize(JavaVM* vm) { - static EnvironmentInitializer init(vm); -} - -/* static */ -JNIEnv* Environment::ensureCurrentThreadIsAttached() { - auto env = g_env->get(); - if (!env) { - FBASSERT(g_vm); - g_vm->AttachCurrentThread(&env, nullptr); - g_env->reset(env); - } - return env; -} - -ThreadScope::ThreadScope() - : attachedWithThisScope_(false) { - JNIEnv* env = nullptr; - if (g_vm->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_EDETACHED) { - return; - } - env = facebook::jni::Environment::ensureCurrentThreadIsAttached(); - FBASSERT(env); - attachedWithThisScope_ = true; -} - -ThreadScope::~ThreadScope() { - if (attachedWithThisScope_) { - Environment::detachCurrentThread(); - } -} - -/* static */ -void ThreadScope::OnLoad() { - // These classes are required for ScopeWithClassLoader. Ensure they are looked up when loading. - JThreadScopeSupport::OnLoad(); -} - -/* static */ -void ThreadScope::WithClassLoader(std::function&& runnable) { - // TODO(cjhopman): If the classloader is already available in this scope, we - // shouldn't have to jump through java. - ThreadScope ts; - JThreadScopeSupport::runStdFunction(std::move(runnable)); -} - -} } - diff --git a/libs/fbjni/src/main/cpp/jni/Exceptions.cpp b/libs/fbjni/src/main/cpp/jni/Exceptions.cpp deleted file mode 100644 index 8ecaba56d..000000000 --- a/libs/fbjni/src/main/cpp/jni/Exceptions.cpp +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - - -namespace facebook { -namespace jni { - -namespace { -class JRuntimeException : public JavaClass { - public: - static auto constexpr kJavaDescriptor = "Ljava/lang/RuntimeException;"; - - static local_ref create(const char* str) { - return newInstance(make_jstring(str)); - } - - static local_ref create() { - return newInstance(); - } -}; - -class JIOException : public JavaClass { - public: - static auto constexpr kJavaDescriptor = "Ljava/io/IOException;"; - - static local_ref create(const char* str) { - return newInstance(make_jstring(str)); - } -}; - -class JOutOfMemoryError : public JavaClass { - public: - static auto constexpr kJavaDescriptor = "Ljava/lang/OutOfMemoryError;"; - - static local_ref create(const char* str) { - return newInstance(make_jstring(str)); - } -}; - -class JArrayIndexOutOfBoundsException : public JavaClass { - public: - static auto constexpr kJavaDescriptor = "Ljava/lang/ArrayIndexOutOfBoundsException;"; - - static local_ref create(const char* str) { - return newInstance(make_jstring(str)); - } -}; - -class JUnknownCppException : public JavaClass { - public: - static auto constexpr kJavaDescriptor = "Lcom/facebook/jni/UnknownCppException;"; - - static local_ref create() { - return newInstance(); - } - - static local_ref create(const char* str) { - return newInstance(make_jstring(str)); - } -}; - -class JCppSystemErrorException : public JavaClass { - public: - static auto constexpr kJavaDescriptor = "Lcom/facebook/jni/CppSystemErrorException;"; - - static local_ref create(const std::system_error& e) { - return newInstance(make_jstring(e.what()), e.code().value()); - } -}; - -// Exception throwing & translating functions ////////////////////////////////////////////////////// - -// Functions that throw Java exceptions - -void setJavaExceptionAndAbortOnFailure(alias_ref throwable) { - auto env = Environment::current(); - if (throwable) { - env->Throw(throwable.get()); - } - if (env->ExceptionCheck() != JNI_TRUE) { - std::abort(); - } -} - -} - -// Functions that throw C++ exceptions - -// TODO(T6618159) Take a stack dump here to save context if it results in a crash when propagated -void throwPendingJniExceptionAsCppException() { - JNIEnv* env = Environment::current(); - if (env->ExceptionCheck() == JNI_FALSE) { - return; - } - - auto throwable = adopt_local(env->ExceptionOccurred()); - if (!throwable) { - throw std::runtime_error("Unable to get pending JNI exception."); - } - env->ExceptionClear(); - - throw JniException(throwable); -} - -void throwCppExceptionIf(bool condition) { - if (!condition) { - return; - } - - auto env = Environment::current(); - if (env->ExceptionCheck() == JNI_TRUE) { - throwPendingJniExceptionAsCppException(); - return; - } - - throw JniException(); -} - -void throwNewJavaException(jthrowable throwable) { - throw JniException(wrap_alias(throwable)); -} - -void throwNewJavaException(const char* throwableName, const char* msg) { - // If anything of the fbjni calls fail, an exception of a suitable - // form will be thrown, which is what we want. - auto throwableClass = findClassLocal(throwableName); - auto throwable = throwableClass->newObject( - throwableClass->getConstructor(), - make_jstring(msg).release()); - throwNewJavaException(throwable.get()); -} - -// Translate C++ to Java Exception - -namespace { - -// The implementation std::rethrow_if_nested uses a dynamic_cast to determine -// if the exception is a nested_exception. If the exception is from a library -// built with -fno-rtti, then that will crash. This avoids that. -void rethrow_if_nested() { - try { - throw; - } catch (const std::nested_exception& e) { - e.rethrow_nested(); - } catch (...) { - } -} - -// For each exception in the chain of the currently handled exception, func -// will be called with that exception as the currently handled exception (in -// reverse order, i.e. innermost first). -void denest(std::function func) { - try { - throw; - } catch (const std::exception& e) { - try { - rethrow_if_nested(); - } catch (...) { - denest(func); - } - func(); - } catch (...) { - func(); - } -} -} - -void translatePendingCppExceptionToJavaException() noexcept { - local_ref previous; - auto func = [&previous] () { - local_ref current; - try { - throw; - } catch(const JniException& ex) { - current = ex.getThrowable(); - } catch(const std::ios_base::failure& ex) { - current = JIOException::create(ex.what()); - } catch(const std::bad_alloc& ex) { - current = JOutOfMemoryError::create(ex.what()); - } catch(const std::out_of_range& ex) { - current = JArrayIndexOutOfBoundsException::create(ex.what()); - } catch(const std::system_error& ex) { - current = JCppSystemErrorException::create(ex); - } catch(const std::runtime_error& ex) { - current = JRuntimeException::create(ex.what()); - } catch(const std::exception& ex) { - current = JCppException::create(ex.what()); - } catch(const char* msg) { - current = JUnknownCppException::create(msg); - } catch(...) { - current = JUnknownCppException::create(); - } - if (previous) { - current->initCause(previous); - } - previous = current; - }; - - try { - denest(func); - setJavaExceptionAndAbortOnFailure(previous); - } catch (std::exception& e) { - FBLOGE("unexpected exception in translatePendingCppExceptionToJavaException: %s", e.what()); - // rethrow the exception and let the noexcept handling abort. - throw; - } catch (...) { - FBLOGE("unexpected exception in translatePendingCppExceptionToJavaException"); - throw; - } -} - -// JniException //////////////////////////////////////////////////////////////////////////////////// - -const std::string JniException::kExceptionMessageFailure_ = "Unable to get exception message."; - -JniException::JniException() : JniException(JRuntimeException::create()) { } - -JniException::JniException(alias_ref throwable) : isMessageExtracted_(false) { - throwable_ = make_global(throwable); -} - -JniException::JniException(JniException &&rhs) - : throwable_(std::move(rhs.throwable_)), - what_(std::move(rhs.what_)), - isMessageExtracted_(rhs.isMessageExtracted_) { -} - -JniException::JniException(const JniException &rhs) - : what_(rhs.what_), isMessageExtracted_(rhs.isMessageExtracted_) { - throwable_ = make_global(rhs.throwable_); -} - -JniException::~JniException() { - ThreadScope ts; - throwable_.reset(); -} - -local_ref JniException::getThrowable() const noexcept { - return make_local(throwable_); -} - -// TODO 6900503: consider making this thread-safe. -void JniException::populateWhat() const noexcept { - ThreadScope ts; - try { - what_ = throwable_->toString(); - isMessageExtracted_ = true; - } catch(...) { - what_ = kExceptionMessageFailure_; - } -} - -const char* JniException::what() const noexcept { - if (!isMessageExtracted_) { - populateWhat(); - } - return what_.c_str(); -} - -void JniException::setJavaException() const noexcept { - setJavaExceptionAndAbortOnFailure(throwable_); -} - -}} diff --git a/libs/fbjni/src/main/cpp/jni/Hybrid.cpp b/libs/fbjni/src/main/cpp/jni/Hybrid.cpp deleted file mode 100644 index 523e2fd27..000000000 --- a/libs/fbjni/src/main/cpp/jni/Hybrid.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "fb/fbjni.h" - - -namespace facebook { -namespace jni { - -namespace detail { - -void HybridData::setNativePointer(std::unique_ptr new_value) { - static auto pointerField = getClass()->getField("mNativePointer"); - auto* old_value = reinterpret_cast(getFieldValue(pointerField)); - if (new_value) { - // Modify should only ever be called once with a non-null - // new_value. If this happens again it's a programmer error, so - // blow up. - FBASSERTMSGF(old_value == 0, "Attempt to set C++ native pointer twice"); - } else if (old_value == 0) { - return; - } - // delete on a null pointer is defined to be a noop. - delete old_value; - // This releases ownership from the unique_ptr, and passes the pointer, and - // ownership of it, to HybridData which is managed by the java GC. The - // finalizer on hybridData calls resetNative which will delete the object, if - // resetNative has not already been called. - setFieldValue(pointerField, reinterpret_cast(new_value.release())); -} - -BaseHybridClass* HybridData::getNativePointer() { - static auto pointerField = getClass()->getField("mNativePointer"); - auto* value = reinterpret_cast(getFieldValue(pointerField)); - if (!value) { - throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException"); - } - return value; -} - -local_ref HybridData::create() { - return newInstance(); -} - -} - -namespace { -void resetNative(alias_ref jthis) { - jthis->setNativePointer(nullptr); -} -} - -void HybridDataOnLoad() { - registerNatives("com/facebook/jni/HybridData", { - makeNativeMethod("resetNative", resetNative), - }); -} - -}} diff --git a/libs/fbjni/src/main/cpp/jni/JThrowable.cpp b/libs/fbjni/src/main/cpp/jni/JThrowable.cpp deleted file mode 100644 index dad42ef29..000000000 --- a/libs/fbjni/src/main/cpp/jni/JThrowable.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "fb/fbjni.h" -#include - -std::string JThrowable::getStackTrace() const { - static auto getStackTraceMethod = javaClassStatic() - ->getMethod()>("getStackTrace"); - - std::ostringstream os; - - auto stackTrace = getStackTraceMethod(self()); - for (size_t i = 0; i < stackTrace->size(); ++i) { - os << facebook::jni::adopt_local((*stackTrace)[i])->toString() << ' '; - } - - return os.str(); -} diff --git a/libs/fbjni/src/main/cpp/jni/OnLoad.cpp b/libs/fbjni/src/main/cpp/jni/OnLoad.cpp deleted file mode 100644 index 228621cbd..000000000 --- a/libs/fbjni/src/main/cpp/jni/OnLoad.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include -#include - -using namespace facebook::jni; - -void initialize_fbjni() { - CountableOnLoad(Environment::current()); - HybridDataOnLoad(); - JNativeRunnable::OnLoad(); - ThreadScope::OnLoad(); -} diff --git a/libs/fbjni/src/main/cpp/jni/References.cpp b/libs/fbjni/src/main/cpp/jni/References.cpp deleted file mode 100644 index 37160cdd1..000000000 --- a/libs/fbjni/src/main/cpp/jni/References.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -namespace facebook { -namespace jni { - -JniLocalScope::JniLocalScope(JNIEnv* env, jint capacity) - : env_(env) { - hasFrame_ = false; - auto pushResult = env->PushLocalFrame(capacity); - FACEBOOK_JNI_THROW_EXCEPTION_IF(pushResult < 0); - hasFrame_ = true; -} - -JniLocalScope::~JniLocalScope() { - if (hasFrame_) { - env_->PopLocalFrame(nullptr); - } -} - -namespace internal { - -// Default implementation always returns true. -// Platform-specific sources can override this. -bool doesGetObjectRefTypeWork() __attribute__ ((weak)); -bool doesGetObjectRefTypeWork() { - return true; -} - -} - -} -} diff --git a/libs/fbjni/src/main/cpp/jni/WeakReference.cpp b/libs/fbjni/src/main/cpp/jni/WeakReference.cpp deleted file mode 100644 index dfaa02f6c..000000000 --- a/libs/fbjni/src/main/cpp/jni/WeakReference.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include - -namespace facebook { -namespace jni { - -WeakReference::WeakReference(jobject strongRef) : - m_weakReference(Environment::current()->NewWeakGlobalRef(strongRef)) -{ -} - -WeakReference::~WeakReference() { - auto env = Environment::current(); - FBASSERTMSGF(env, "Attempt to delete jni::WeakReference from non-JNI thread"); - env->DeleteWeakGlobalRef(m_weakReference); -} - -ResolvedWeakReference::ResolvedWeakReference(jobject weakRef) : - m_strongReference(Environment::current()->NewLocalRef(weakRef)) -{ -} - -ResolvedWeakReference::ResolvedWeakReference(const RefPtr& weakRef) : - m_strongReference(Environment::current()->NewLocalRef(weakRef->weakRef())) -{ -} - -ResolvedWeakReference::~ResolvedWeakReference() { - if (m_strongReference) - Environment::current()->DeleteLocalRef(m_strongReference); -} - -} } - diff --git a/libs/fbjni/src/main/cpp/jni/jni_helpers.cpp b/libs/fbjni/src/main/cpp/jni/jni_helpers.cpp deleted file mode 100644 index b6ad63545..000000000 --- a/libs/fbjni/src/main/cpp/jni/jni_helpers.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include - -#include - -#define MSG_SIZE 1024 - -namespace facebook { - -/** - * Instructs the JNI environment to throw an exception. - * - * @param pEnv JNI environment - * @param szClassName class name to throw - * @param szFmt sprintf-style format string - * @param ... sprintf-style args - * @return 0 on success; a negative value on failure - */ -jint throwException(JNIEnv* pEnv, const char* szClassName, const char* szFmt, va_list va_args) { - char szMsg[MSG_SIZE]; - vsnprintf(szMsg, MSG_SIZE, szFmt, va_args); - jclass exClass = pEnv->FindClass(szClassName); - return pEnv->ThrowNew(exClass, szMsg); -} - -/** - * Instructs the JNI environment to throw a NoClassDefFoundError. - * - * @param pEnv JNI environment - * @param szFmt sprintf-style format string - * @param ... sprintf-style args - * @return 0 on success; a negative value on failure - */ -jint throwNoClassDefError(JNIEnv* pEnv, const char* szFmt, ...) { - va_list va_args; - va_start(va_args, szFmt); - jint ret = throwException(pEnv, "java/lang/NoClassDefFoundError", szFmt, va_args); - va_end(va_args); - return ret; -} - -/** - * Instructs the JNI environment to throw a RuntimeException. - * - * @param pEnv JNI environment - * @param szFmt sprintf-style format string - * @param ... sprintf-style args - * @return 0 on success; a negative value on failure - */ -jint throwRuntimeException(JNIEnv* pEnv, const char* szFmt, ...) { - va_list va_args; - va_start(va_args, szFmt); - jint ret = throwException(pEnv, "java/lang/RuntimeException", szFmt, va_args); - va_end(va_args); - return ret; -} - -/** - * Instructs the JNI environment to throw an IllegalArgumentException. - * - * @param pEnv JNI environment - * @param szFmt sprintf-style format string - * @param ... sprintf-style args - * @return 0 on success; a negative value on failure - */ -jint throwIllegalArgumentException(JNIEnv* pEnv, const char* szFmt, ...) { - va_list va_args; - va_start(va_args, szFmt); - jint ret = throwException(pEnv, "java/lang/IllegalArgumentException", szFmt, va_args); - va_end(va_args); - return ret; -} - -/** - * Instructs the JNI environment to throw an IllegalStateException. - * - * @param pEnv JNI environment - * @param szFmt sprintf-style format string - * @param ... sprintf-style args - * @return 0 on success; a negative value on failure - */ -jint throwIllegalStateException(JNIEnv* pEnv, const char* szFmt, ...) { - va_list va_args; - va_start(va_args, szFmt); - jint ret = throwException(pEnv, "java/lang/IllegalStateException", szFmt, va_args); - va_end(va_args); - return ret; -} - -/** - * Instructs the JNI environment to throw an OutOfMemoryError. - * - * @param pEnv JNI environment - * @param szFmt sprintf-style format string - * @param ... sprintf-style args - * @return 0 on success; a negative value on failure - */ -jint throwOutOfMemoryError(JNIEnv* pEnv, const char* szFmt, ...) { - va_list va_args; - va_start(va_args, szFmt); - jint ret = throwException(pEnv, "java/lang/OutOfMemoryError", szFmt, va_args); - va_end(va_args); - return ret; -} - -/** - * Instructs the JNI environment to throw an AssertionError. - * - * @param pEnv JNI environment - * @param szFmt sprintf-style format string - * @param ... sprintf-style args - * @return 0 on success; a negative value on failure - */ -jint throwAssertionError(JNIEnv* pEnv, const char* szFmt, ...) { - va_list va_args; - va_start(va_args, szFmt); - jint ret = throwException(pEnv, "java/lang/AssertionError", szFmt, va_args); - va_end(va_args); - return ret; -} - -/** - * Instructs the JNI environment to throw an IOException. - * - * @param pEnv JNI environment - * @param szFmt sprintf-style format string - * @param ... sprintf-style args - * @return 0 on success; a negative value on failure - */ -jint throwIOException(JNIEnv* pEnv, const char* szFmt, ...) { - va_list va_args; - va_start(va_args, szFmt); - jint ret = throwException(pEnv, "java/io/IOException", szFmt, va_args); - va_end(va_args); - return ret; -} - -/** - * Finds the specified class. If it's not found, instructs the JNI environment to throw an - * exception. - * - * @param pEnv JNI environment - * @param szClassName the classname to find in JNI format (e.g. "java/lang/String") - * @return the class or NULL if not found (in which case a pending exception will be queued). This - * returns a global reference (JNIEnv::NewGlobalRef). - */ -jclass findClassOrThrow(JNIEnv* pEnv, const char* szClassName) { - jclass clazz = pEnv->FindClass(szClassName); - if (!clazz) { - return NULL; - } - return (jclass) pEnv->NewGlobalRef(clazz); -} - -/** - * Finds the specified field of the specified class. If it's not found, instructs the JNI - * environment to throw an exception. - * - * @param pEnv JNI environment - * @param clazz the class to lookup the field in - * @param szFieldName the name of the field to find - * @param szSig the signature of the field - * @return the field or NULL if not found (in which case a pending exception will be queued) - */ -jfieldID getFieldIdOrThrow(JNIEnv* pEnv, jclass clazz, const char* szFieldName, const char* szSig) { - return pEnv->GetFieldID(clazz, szFieldName, szSig); -} - -/** - * Finds the specified method of the specified class. If it's not found, instructs the JNI - * environment to throw an exception. - * - * @param pEnv JNI environment - * @param clazz the class to lookup the method in - * @param szMethodName the name of the method to find - * @param szSig the signature of the method - * @return the method or NULL if not found (in which case a pending exception will be queued) - */ -jmethodID getMethodIdOrThrow( - JNIEnv* pEnv, - jclass clazz, - const char* szMethodName, - const char* szSig) { - return pEnv->GetMethodID(clazz, szMethodName, szSig); -} - -} // namespace facebook diff --git a/libs/fbjni/src/main/cpp/log.cpp b/libs/fbjni/src/main/cpp/log.cpp deleted file mode 100644 index b6baa2dad..000000000 --- a/libs/fbjni/src/main/cpp/log.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include -#include - -#define LOG_BUFFER_SIZE 4096 -static LogHandler gLogHandler; - -void setLogHandler(LogHandler logHandler) { - gLogHandler = logHandler; -} - -int fb_printLog(int prio, const char *tag, const char *fmt, ...) { - char logBuffer[LOG_BUFFER_SIZE]; - - va_list va_args; - va_start(va_args, fmt); - int result = vsnprintf(logBuffer, sizeof(logBuffer), fmt, va_args); - va_end(va_args); - if (gLogHandler != NULL) { - gLogHandler(prio, tag, logBuffer); - } - __android_log_write(prio, tag, logBuffer); - return result; -} - -void logPrintByDelims(int priority, const char* tag, const char* delims, - const char* msg, ...) -{ - va_list ap; - char buf[32768]; - char* context; - char* tok; - - va_start(ap, msg); - vsnprintf(buf, sizeof(buf), msg, ap); - va_end(ap); - - tok = strtok_r(buf, delims, &context); - - if (!tok) { - return; - } - - do { - __android_log_write(priority, tag, tok); - } while ((tok = strtok_r(NULL, delims, &context))); -} - -#ifndef ANDROID - -// Implementations of the basic android logging functions for non-android platforms. - -static char logTagChar(int prio) { - switch (prio) { - default: - case ANDROID_LOG_UNKNOWN: - case ANDROID_LOG_DEFAULT: - case ANDROID_LOG_SILENT: - return ' '; - case ANDROID_LOG_VERBOSE: - return 'V'; - case ANDROID_LOG_DEBUG: - return 'D'; - case ANDROID_LOG_INFO: - return 'I'; - case ANDROID_LOG_WARN: - return 'W'; - case ANDROID_LOG_ERROR: - return 'E'; - case ANDROID_LOG_FATAL: - return 'F'; - } -} - -int __android_log_write(int prio, const char *tag, const char *text) { - return fprintf(stderr, "[%c/%.16s] %s\n", logTagChar(prio), tag, text); -} - -int __android_log_print(int prio, const char *tag, const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - - int res = fprintf(stderr, "[%c/%.16s] ", logTagChar(prio), tag); - res += vfprintf(stderr, "%s\n", ap); - - va_end(ap); - return res; -} - -#endif diff --git a/libs/fbjni/src/main/cpp/onload.cpp b/libs/fbjni/src/main/cpp/onload.cpp deleted file mode 100644 index 0594526d3..000000000 --- a/libs/fbjni/src/main/cpp/onload.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#ifndef DISABLE_CPUCAP -#include -#endif -#include - -using namespace facebook::jni; - -void initialize_xplatinit(); -void initialize_fbjni(); - -JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - return facebook::jni::initialize(vm, [] { - initialize_fbjni(); -#ifndef DISABLE_XPLAT - initialize_xplatinit(); -#endif -#ifndef DISABLE_CPUCAP - initialize_cpucapabilities(); -#endif - }); -} diff --git a/libs/fbjni/src/main/java/com/facebook/jni/BUCK b/libs/fbjni/src/main/java/com/facebook/jni/BUCK deleted file mode 100644 index 87983dd47..000000000 --- a/libs/fbjni/src/main/java/com/facebook/jni/BUCK +++ /dev/null @@ -1,20 +0,0 @@ -# BUILD FILE SYNTAX: SKYLARK -# Copyright (c) 2017-present, Facebook, Inc. -# -# This source code is licensed under the Apache 2.0 license found in the -# LICENSE file in the root directory of this source tree. -load("//:LITHO_DEFS.bzl", "LITHO_JSR_TARGET", "LITHO_PROGUARDANNOTATIONS_TARGET", "LITHO_SOLOADER_TARGET", "fb_java_library") - -fb_java_library( - name = "jni", - srcs = glob(["**/*.java"]), - proguard_config = "fbjni.pro", - visibility = [ - "PUBLIC", - ], - deps = [ - LITHO_PROGUARDANNOTATIONS_TARGET, - LITHO_SOLOADER_TARGET, - LITHO_JSR_TARGET, - ], -) diff --git a/libs/fbjni/src/main/java/com/facebook/jni/Countable.java b/libs/fbjni/src/main/java/com/facebook/jni/Countable.java deleted file mode 100644 index f8e343da2..000000000 --- a/libs/fbjni/src/main/java/com/facebook/jni/Countable.java +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -package com.facebook.jni; - -import com.facebook.proguard.annotations.DoNotStrip; - -/** - * A Java Object that has native memory allocated corresponding to this instance. - * - * NB: THREAD SAFETY (this comment also exists at Countable.cpp) - * - * {@link #dispose} deletes the corresponding native object on whatever thread the method is called - * on. In the common case when this is called by Countable#finalize(), this will be called on the - * system finalizer thread. If you manually call dispose on the Java object, the native object - * will be deleted synchronously on that thread. - */ -@DoNotStrip -public class Countable { - - // Private C++ instance - @DoNotStrip - private long mInstance = 0; - - public native void dispose(); - - protected void finalize() throws Throwable { - dispose(); - super.finalize(); - } -} diff --git a/libs/fbjni/src/main/java/com/facebook/jni/CppException.java b/libs/fbjni/src/main/java/com/facebook/jni/CppException.java deleted file mode 100644 index 6308d5dc2..000000000 --- a/libs/fbjni/src/main/java/com/facebook/jni/CppException.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.jni; - -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip -public class CppException extends RuntimeException { - @DoNotStrip - public CppException(String message) { - super(message); - } -} diff --git a/libs/fbjni/src/main/java/com/facebook/jni/CppSystemErrorException.java b/libs/fbjni/src/main/java/com/facebook/jni/CppSystemErrorException.java deleted file mode 100644 index 942a61714..000000000 --- a/libs/fbjni/src/main/java/com/facebook/jni/CppSystemErrorException.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.jni; - -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip -public class CppSystemErrorException extends CppException { - int errorCode; - - @DoNotStrip - public CppSystemErrorException(String message, int errorCode) { - super(message); - this.errorCode = errorCode; - } - - public int getErrorCode() { - return errorCode; - } -} diff --git a/libs/fbjni/src/main/java/com/facebook/jni/HybridClassBase.java b/libs/fbjni/src/main/java/com/facebook/jni/HybridClassBase.java deleted file mode 100644 index 3e39175c4..000000000 --- a/libs/fbjni/src/main/java/com/facebook/jni/HybridClassBase.java +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2004-present, Facebook, Inc. - -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package com.facebook.jni; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip -public abstract class HybridClassBase extends HybridData { -} diff --git a/libs/fbjni/src/main/java/com/facebook/jni/HybridData.java b/libs/fbjni/src/main/java/com/facebook/jni/HybridData.java deleted file mode 100644 index 35803a563..000000000 --- a/libs/fbjni/src/main/java/com/facebook/jni/HybridData.java +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -package com.facebook.jni; - -import com.facebook.proguard.annotations.DoNotStrip; - -/** - * This object holds a native C++ member for hybrid Java/C++ objects. - * - * NB: THREAD SAFETY - * - * {@link #dispose} deletes the corresponding native object on whatever thread - * the method is called on. In the common case when this is called by - * HybridData#finalize(), this will be called on the system finalizer - * thread. If you manually call resetNative() on the Java object, the C++ - * object will be deleted synchronously on that thread. - */ -@DoNotStrip -public class HybridData { - - // Private C++ instance - @DoNotStrip - private long mNativePointer = 0; - - /** - * To explicitly delete the instance, call resetNative(). If the C++ - * instance is referenced after this is called, a NullPointerException will - * be thrown. resetNative() may be called multiple times safely. Because - * {@link #finalize} calls resetNative, the instance will not leak if this is - * not called, but timing of deletion and the thread the C++ dtor is called - * on will be at the whim of the Java GC. If you want to control the thread - * and timing of the destructor, you should call resetNative() explicitly. - */ - public native void resetNative(); - - protected void finalize() throws Throwable { - resetNative(); - super.finalize(); - } - - public boolean isValid() { - return mNativePointer != 0; - } -} diff --git a/libs/fbjni/src/main/java/com/facebook/jni/IteratorHelper.java b/libs/fbjni/src/main/java/com/facebook/jni/IteratorHelper.java deleted file mode 100644 index 928870d2b..000000000 --- a/libs/fbjni/src/main/java/com/facebook/jni/IteratorHelper.java +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.jni; - -import com.facebook.proguard.annotations.DoNotStrip; - -import javax.annotation.Nullable; - -import java.util.Iterator; - -/** - * To iterate over an Iterator from C++ requires two calls per entry: hasNext() - * and next(). This helper reduces it to one call and one field get per entry. - * It does not use a generic argument, since in C++, the types will be erased, - * anyway. This is *not* a {@link java.util.Iterator}. - */ -@DoNotStrip -public class IteratorHelper { - private final Iterator mIterator; - - // This is private, but accessed via JNI. - @DoNotStrip - private @Nullable Object mElement; - - @DoNotStrip - public IteratorHelper(Iterator iterator) { - mIterator = iterator; - } - - @DoNotStrip - public IteratorHelper(Iterable iterable) { - mIterator = iterable.iterator(); - } - - /** - * Moves the helper to the next entry in the map, if any. Returns true iff - * there is an entry to read. - */ - @DoNotStrip - boolean hasNext() { - if (mIterator.hasNext()) { - mElement = mIterator.next(); - return true; - } else { - mElement = null; - return false; - } - } -} diff --git a/libs/fbjni/src/main/java/com/facebook/jni/MapIteratorHelper.java b/libs/fbjni/src/main/java/com/facebook/jni/MapIteratorHelper.java deleted file mode 100644 index e50cd7d56..000000000 --- a/libs/fbjni/src/main/java/com/facebook/jni/MapIteratorHelper.java +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.jni; - -import javax.annotation.Nullable; - -import java.util.Iterator; -import java.util.Map; - -import com.facebook.proguard.annotations.DoNotStrip; - -/** - * To iterate over a Map from C++ requires four calls per entry: hasNext(), - * next(), getKey(), getValue(). This helper reduces it to one call and two - * field gets per entry. It does not use a generic argument, since in C++, the - * types will be erased, anyway. This is *not* a {@link java.util.Iterator}. - */ -@DoNotStrip -public class MapIteratorHelper { - @DoNotStrip private final Iterator mIterator; - @DoNotStrip private @Nullable Object mKey; - @DoNotStrip private @Nullable Object mValue; - - @DoNotStrip - public MapIteratorHelper(Map map) { - mIterator = map.entrySet().iterator(); - } - - /** - * Moves the helper to the next entry in the map, if any. Returns true iff - * there is an entry to read. - */ - @DoNotStrip - boolean hasNext() { - if (mIterator.hasNext()) { - Map.Entry entry = mIterator.next(); - mKey = entry.getKey(); - mValue = entry.getValue(); - return true; - } else { - mKey = null; - mValue = null; - return false; - } - } -} diff --git a/libs/fbjni/src/main/java/com/facebook/jni/NativeRunnable.java b/libs/fbjni/src/main/java/com/facebook/jni/NativeRunnable.java deleted file mode 100644 index 34216a29c..000000000 --- a/libs/fbjni/src/main/java/com/facebook/jni/NativeRunnable.java +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.jni; - -import com.facebook.jni.HybridData; -import com.facebook.proguard.annotations.DoNotStrip; - -/** - * A Runnable that has a native run implementation. - */ -@DoNotStrip -public class NativeRunnable implements Runnable { - - private final HybridData mHybridData; - - private NativeRunnable(HybridData hybridData) { - mHybridData = hybridData; - } - - public native void run(); -} diff --git a/libs/fbjni/src/main/java/com/facebook/jni/ThreadScopeSupport.java b/libs/fbjni/src/main/java/com/facebook/jni/ThreadScopeSupport.java deleted file mode 100644 index bda99d622..000000000 --- a/libs/fbjni/src/main/java/com/facebook/jni/ThreadScopeSupport.java +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -package com.facebook.jni; - -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip -public class ThreadScopeSupport { - // This is just used for ThreadScope::withClassLoader to have a java function - // in the stack so that jni has access to the correct classloader. - @DoNotStrip - private static void runStdFunction(long ptr) { - runStdFunctionImpl(ptr); - } - - private static native void runStdFunctionImpl(long ptr); -} diff --git a/libs/fbjni/src/main/java/com/facebook/jni/UnknownCppException.java b/libs/fbjni/src/main/java/com/facebook/jni/UnknownCppException.java deleted file mode 100644 index 902159d9f..000000000 --- a/libs/fbjni/src/main/java/com/facebook/jni/UnknownCppException.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.jni; - -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip -public class UnknownCppException extends CppException { - @DoNotStrip - public UnknownCppException() { - super("Unknown"); - } - - @DoNotStrip - public UnknownCppException(String message) { - super(message); - } -} diff --git a/libs/fbjni/src/main/java/com/facebook/jni/fbjni.pro b/libs/fbjni/src/main/java/com/facebook/jni/fbjni.pro deleted file mode 100644 index 5b5b6454d..000000000 --- a/libs/fbjni/src/main/java/com/facebook/jni/fbjni.pro +++ /dev/null @@ -1,11 +0,0 @@ -# For common use cases for the hybrid pattern, keep symbols which may -# be referenced only from C++. - --keepclassmembers class * { - com.facebook.jni.HybridData *; - (com.facebook.jni.HybridData); -} - --keepclasseswithmembers class * { - com.facebook.jni.HybridData *; -}