├── .gitignore ├── DumpPrinter ├── .gitignore ├── build.gradle └── src │ └── com │ └── dodola │ └── alloc │ └── dump │ ├── AllocationInfo.java │ ├── HandleHeap.java │ ├── IStackTraceInfo.java │ └── Main.java ├── README.md ├── alloctrackSample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── dodola │ │ └── alloctrack │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── cpp │ │ ├── CMakeLists.txt │ │ ├── Substrate │ │ │ ├── Buffer.hpp │ │ │ ├── CMakeLists.txt │ │ │ ├── CydiaSubstrate.h │ │ │ ├── SubstrateARM.hpp │ │ │ ├── SubstrateDebug.cpp │ │ │ ├── SubstrateDebug.hpp │ │ │ ├── SubstrateHook.cpp │ │ │ ├── SubstrateHook.h │ │ │ ├── SubstrateLog.hpp │ │ │ ├── SubstratePosixMemory.cpp │ │ │ ├── SubstrateX86.hpp │ │ │ ├── hde64.c │ │ │ ├── hde64.h │ │ │ └── table64.h │ │ ├── allocTracker.cpp │ │ ├── alloctracker.h │ │ ├── dlopen.c │ │ ├── dlopen.h │ │ ├── fb │ │ │ ├── CMakeLists.txt │ │ │ ├── fbjni │ │ │ │ ├── ByteBuffer.cpp │ │ │ │ ├── ByteBuffer.h │ │ │ │ ├── Context.h │ │ │ │ ├── File.h │ │ │ │ ├── JThread.h │ │ │ │ ├── NativeRunnable.h │ │ │ │ ├── OnLoad.cpp │ │ │ │ ├── ReadableByteChannel.cpp │ │ │ │ ├── ReadableByteChannel.h │ │ │ │ ├── detail │ │ │ │ │ ├── Boxed.h │ │ │ │ │ ├── Common.h │ │ │ │ │ ├── CoreClasses-inl.h │ │ │ │ │ ├── CoreClasses.h │ │ │ │ │ ├── Environment.cpp │ │ │ │ │ ├── Environment.h │ │ │ │ │ ├── Exceptions.cpp │ │ │ │ │ ├── Exceptions.h │ │ │ │ │ ├── Hybrid.cpp │ │ │ │ │ ├── Hybrid.h │ │ │ │ │ ├── Iterator-inl.h │ │ │ │ │ ├── Iterator.h │ │ │ │ │ ├── JWeakReference.h │ │ │ │ │ ├── Log.h │ │ │ │ │ ├── Meta-forward.h │ │ │ │ │ ├── Meta-inl.h │ │ │ │ │ ├── Meta.h │ │ │ │ │ ├── MetaConvert.h │ │ │ │ │ ├── ReferenceAllocators-inl.h │ │ │ │ │ ├── ReferenceAllocators.h │ │ │ │ │ ├── References-forward.h │ │ │ │ │ ├── References-inl.h │ │ │ │ │ ├── References.cpp │ │ │ │ │ ├── References.h │ │ │ │ │ ├── Registration-inl.h │ │ │ │ │ ├── Registration.h │ │ │ │ │ ├── TypeTraits.h │ │ │ │ │ ├── utf8.cpp │ │ │ │ │ └── utf8.h │ │ │ │ ├── fbjni.cpp │ │ │ │ └── fbjni.h │ │ │ └── lyra │ │ │ │ ├── cxa_throw.cpp │ │ │ │ ├── lyra.cpp │ │ │ │ ├── lyra.h │ │ │ │ ├── lyra_breakpad.cpp │ │ │ │ ├── lyra_exceptions.cpp │ │ │ │ └── lyra_exceptions.h │ │ ├── lock.cpp │ │ ├── lock.h │ │ ├── logger.h │ │ └── native-lib.cpp │ ├── java │ │ └── com │ │ │ └── dodola │ │ │ └── alloctrack │ │ │ ├── AllocTracker.java │ │ │ └── MainActivity.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── dodola │ └── alloctrack │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screen.png ├── settings.gradle └── tools └── DumpPrinter-1.0.jar /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # IntelliJ 36 | *.iml 37 | .idea/workspace.xml 38 | .idea/tasks.xml 39 | .idea/gradle.xml 40 | .idea/assetWizardSettings.xml 41 | .idea/dictionaries 42 | .idea/libraries 43 | .idea/caches 44 | .cxx/ 45 | .idea/ 46 | .gradle/ 47 | 48 | # Keystore files 49 | # Uncomment the following line if you do not want to check your keystore files in. 50 | #*.jks 51 | 52 | # External native build folder generated in Android Studio 2.2 and later 53 | .externalNativeBuild 54 | 55 | # Google Services (e.g. APIs or Firebase) 56 | google-services.json 57 | 58 | # Freeline 59 | freeline.py 60 | freeline/ 61 | freeline_project_description.json 62 | 63 | # fastlane 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | fastlane/readme.md 69 | -------------------------------------------------------------------------------- /DumpPrinter/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /tools_output -------------------------------------------------------------------------------- /DumpPrinter/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | 4 | 5 | version 1.0 6 | 7 | dependencies { 8 | implementation fileTree(include: ['*.jar'], dir: 'libs') 9 | } 10 | 11 | 12 | jar { 13 | manifest { 14 | attributes 'Main-Class': 'com.dodola.alloc.dump.Main' 15 | attributes 'Manifest-Version': version 16 | } 17 | 18 | from { 19 | exclude 'META-INF/MANIFEST.MF' 20 | exclude 'META-INF/*.SF' 21 | exclude 'META-INF/*.DSA' 22 | exclude 'META-INF/*.RSA' 23 | configurations.runtime.resolve().collect { 24 | it.isDirectory() ? it : zipTree(it) 25 | } 26 | } 27 | } 28 | 29 | // copy the jar to work directory 30 | task buildAlloctrackJar(type: Copy, dependsOn: [build, jar]) { 31 | group = "buildTool" 32 | from('build/libs') { 33 | include '*.jar' 34 | exclude '*-javadoc.jar' 35 | exclude '*-sources.jar' 36 | } 37 | into(rootProject.file("tools")) 38 | } 39 | -------------------------------------------------------------------------------- /DumpPrinter/src/com/dodola/alloc/dump/AllocationInfo.java: -------------------------------------------------------------------------------- 1 | package com.dodola.alloc.dump; 2 | 3 | public class AllocationInfo implements Comparable, IStackTraceInfo { 4 | private String mAllocatedClass; 5 | private int mAllocationSize; 6 | private short mThreadId; 7 | private StackTraceElement[] mStackTrace; 8 | /* 9 | * Simple constructor. 10 | */ 11 | AllocationInfo(String allocatedClass, int allocationSize, 12 | short threadId, StackTraceElement[] stackTrace) { 13 | mAllocatedClass = allocatedClass; 14 | mAllocationSize = allocationSize; 15 | mThreadId = threadId; 16 | mStackTrace = stackTrace; 17 | } 18 | 19 | /** 20 | * Returns the name of the allocated class. 21 | */ 22 | public String getAllocatedClass() { 23 | return mAllocatedClass; 24 | } 25 | /** 26 | * Returns the size of the allocation. 27 | */ 28 | public int getSize() { 29 | return mAllocationSize; 30 | } 31 | /** 32 | * Returns the id of the thread that performed the allocation. 33 | */ 34 | public short getThreadId() { 35 | return mThreadId; 36 | } 37 | /* 38 | * (non-Javadoc) 39 | * @see com.android.ddmlib.IStackTraceInfo#getStackTrace() 40 | */ 41 | public StackTraceElement[] getStackTrace() { 42 | return mStackTrace; 43 | } 44 | public int compareTo(AllocationInfo otherAlloc) { 45 | return otherAlloc.mAllocationSize - mAllocationSize; 46 | } 47 | } -------------------------------------------------------------------------------- /DumpPrinter/src/com/dodola/alloc/dump/IStackTraceInfo.java: -------------------------------------------------------------------------------- 1 | package com.dodola.alloc.dump; 2 | 3 | public interface IStackTraceInfo { 4 | /** 5 | * Returns the stack trace. This can be null. 6 | */ 7 | public StackTraceElement[] getStackTrace(); 8 | } -------------------------------------------------------------------------------- /DumpPrinter/src/com/dodola/alloc/dump/Main.java: -------------------------------------------------------------------------------- 1 | package com.dodola.alloc.dump; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.IOException; 5 | import java.nio.ByteBuffer; 6 | import java.nio.channels.FileChannel; 7 | import java.util.ArrayList; 8 | 9 | public class Main { 10 | 11 | public static void main(String[] args) throws IOException { 12 | if (args.length > 0) { 13 | String filePath = args[0]; 14 | FileInputStream fIn = new FileInputStream(filePath); 15 | FileChannel fChan = fIn.getChannel(); 16 | long fSize = fChan.size(); 17 | ByteBuffer mBuf = ByteBuffer.allocate((int) fSize); 18 | fChan.read(mBuf); 19 | mBuf.rewind(); 20 | ArrayList allocationInfos = HandleHeap.handleRecentAlloc(mBuf); 21 | HandleHeap.dumpRecords(allocationInfos); 22 | } else { 23 | System.out.println("请传入日志地址"); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chapter03 2 | 3 | **这个 Sample 难度的确有点大,我们可以看着例子中的一些 Hook 点去找源码中对应的实现,看看为什么不同的版本要使用不同的实现方式。** 4 | 5 | 该例子主要实现了在运行时动态获取对象分配的情况,可以运用在自动化的分析中。 6 | 7 | 目的是展示一种模仿 Android Profiler,但可以脱离 Profiler 实现自动化内存分配分析的方案。 8 | 9 | 我们可以在它基础上做很多自定义的操作: 10 | 1. 追踪Bitmap的创建堆栈; 11 | 2. 追踪线程的创建堆栈; 12 | 3. 追踪特定对象的分配; 13 | 4. ... 14 | 15 | 在后面我们也会有大量的这些例子,只要充分清楚底层原理,我们可以做到事情还是很多的。 16 | 17 | **在高版本 Android Profiler 使用了新的方法来实现 Allocation Tracker,这块我们后面在的章节会给出新的实现。** 18 | 19 | 开发环境 20 | ======= 21 | Android Studio 3.2.1 22 | NDK 16~19 23 | 24 | 运行环境 25 | ====== 26 | 支持 ARMv7a 和 x86平台 27 | 项目支持Dalvik 和 Art 虚拟机,理论上兼容了4.0到9.0的机型,在7.1到9.0的手机和模拟器上已经跑通,比较稳定。 28 | 由于国内机型的差异化,无法适配所有机型,项目只做展示原理使用,并不稳定。 29 | 30 | 使用方式 31 | ====== 32 | 33 | 1. 点击`开始记录`即可触发对象分配记录会在 logcat 中看见如下日志 34 | ``` 35 | /com.dodola.alloctrack I/AllocTracker: ====current alloc count 111===== 36 | ``` 37 | 说明已经开始记录对象的分配 38 | 39 | 2. 当对象达到设置的最大数量的时候触发内存 dump,会有如下日志 40 | ``` 41 | com.dodola.alloctrack I/AllocTracker: saveARTAllocationData /data/user/0/com.dodola.alloctrack/files/1544005106 file, fd: 63 42 | com.dodola.alloctrack I/AllocTracker: saveARTAllocationData write file to /data/user/0/com.dodola.alloctrack/files/1544005106 43 | ``` 44 | 45 | 46 | 3. 数据会保存在 `/data/data/com.dodola.alloctrack/files`目录下 47 | 48 | 4. 数据解析。采集下来的数据无法直接通过编辑器打开,需要通过 dumpprinter 工具来进行解析,操作如下 49 | ``` 50 | dump 工具存放在tools/DumpPrinter-1.0.jar 中 51 | 52 | 可以通过 gradle task :buildAlloctracker.jar编译 53 | 54 | //调用方法: 55 | java -jar tools/DumpPrinter-1.0.jar dump文件路径 > dump_log.txt 56 | ``` 57 | 58 | 5. 然后就可以在 `dump_log.txt` 中看到解析出来的数据 59 | 采集到的数据基本格式如下: 60 | 61 | ``` 62 | Found 10240 records://dump 下来的数据包含对象数量 63 | tid=7205 java.lang.Class (4144 bytes)//当前线程 类名 分配的大小 64 | //下面是分配该对象的时候当前线程的堆栈信息 65 | android.support.v7.widget.Toolbar.ensureMenuView (Toolbar.java:1047) 66 | android.support.v7.widget.Toolbar.setMenu (Toolbar.java:551) 67 | android.support.v7.widget.ToolbarWidgetWrapper.setMenu (ToolbarWidgetWrapper.java:370) 68 | android.support.v7.widget.ActionBarOverlayLayout.setMenu (ActionBarOverlayLayout.java:721) 69 | android.support.v7.app.AppCompatDelegateImpl.preparePanel (AppCompatDelegateImpl.java:1583) 70 | android.support.v7.app.AppCompatDelegateImpl.doInvalidatePanelMenu (AppCompatDelegateImpl.java:1869) 71 | android.support.v7.app.AppCompatDelegateImpl$2.run (AppCompatDelegateImpl.java:230) 72 | android.os.Handler.handleCallback (Handler.java:792) 73 | android.os.Handler.dispatchMessage (Handler.java:98) 74 | android.os.Looper.loop (Looper.java:176) 75 | android.app.ActivityThread.main (ActivityThread.java:6701) 76 | java.lang.reflect.Method.invoke (Native method) 77 | com.android.internal.os.Zygote$MethodAndArgsCaller.run (Zygote.java:246) 78 | com.android.internal.os.ZygoteInit.main (ZygoteInit.java:783) 79 | ``` 80 | 81 | 原理解析 82 | ====== 83 | 项目使用了 inline hook 来拦截内存对象分配时候的 `RecordAllocation` 函数,通过拦截该接口可以快速获取到当时分配对象的类名和分配的内存大小。 84 | 85 | 在初始化的时候我们设置了一个分配对象数量的最大值,如果从 start 开始对象分配数量超过最大值就会触发内存 dump,然后清空 alloc 对象列表,重新计算。该功能和 Android Studio 里的 Allocation Tracker 类似,只不过可以在代码级别更细粒度的进行控制。可以精确到方法级别。 86 | 87 | 核心点如下: 88 | 89 | 1. 阅读源码。各个ROM版本的实现有所差异,我们需要在各个版本上面找到合适的 Hook 点。这里需要我们对整个流程和原理都比较清楚。 90 | 2. 选择合适的框架。需要对各种Hook框架有清楚的认识,如何选择,如何使用。 91 | 92 | 这套方案的确有点复杂,Android Profiler 换了新的实现方案。整体实现会简单很多,后续也会给出实现。 93 | 94 | Thanks 95 | ====== 96 | Substrate 一款经典的 hook 框架 97 | 98 | [fbjni](https://github.com/facebookincubator/profilo/tree/master/deps/fbjni) 是从 Facebook 开源的一款jni工具类库,主要提供了工具类,ref utils ,Global JniEnv。 99 | 100 | [ndk_dlopen](https://github.com/rrrfff/ndk_dlopen) 提供了force dlopen 机制 101 | -------------------------------------------------------------------------------- /alloctrackSample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /alloctrackSample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "com.dodola.alloctrack" 7 | minSdkVersion 14 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | externalNativeBuild { 13 | cmake { 14 | abiFilters "armeabi-v7a","x86" 15 | } 16 | } 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | externalNativeBuild { 25 | cmake { 26 | path "src/main/cpp/CMakeLists.txt" 27 | } 28 | } 29 | } 30 | 31 | dependencies { 32 | implementation fileTree(dir: 'libs', include: ['*.jar']) 33 | implementation 'com.android.support:appcompat-v7:28.0.0' 34 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 35 | testImplementation 'junit:junit:4.12' 36 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 37 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 38 | } 39 | -------------------------------------------------------------------------------- /alloctrackSample/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /alloctrackSample/src/androidTest/java/com/dodola/alloctrack/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.dodola.alloctrack; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.dodola.alloctrack", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # For more information about using CMake with Android Studio, read the 2 | # documentation: https://d.android.com/studio/projects/add-native-code.html 3 | 4 | # Sets the minimum version of CMake required to build the native library. 5 | 6 | cmake_minimum_required(VERSION 3.6) 7 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions -Wno-unused -Wno-gnu-alignof-expression -Wno-missing-field-initializers -std=c++11 -fvisibility=hidden -fexceptions -Wextra -Wno-unused-parameter -Wno-format-security -Wno-unused-local-typedef") 8 | # Creates and names a library, sets it as either STATIC 9 | # or SHARED, and provides the relative paths to its source code. 10 | # You can define multiple libraries, and CMake builds them for you. 11 | # Gradle automatically packages shared libraries with your APK. 12 | add_subdirectory(fb) 13 | add_subdirectory(Substrate) 14 | #add_subdirectory(HookZz) 15 | 16 | include_directories(fb) 17 | add_library( # Sets the name of the library. 18 | alloc-lib 19 | SHARED 20 | dlopen.c 21 | allocTracker.cpp 22 | lock.cpp 23 | native-lib.cpp) 24 | 25 | # Searches for a specified prebuilt library and stores the path as a 26 | # variable. Because CMake includes system libraries in the search path by 27 | # default, you only need to specify the name of the public NDK library 28 | # you want to add. CMake verifies that the library exists before 29 | # completing its build. 30 | 31 | find_library( # Sets the name of the path variable. 32 | log-lib 33 | 34 | # Specifies the name of the NDK library that 35 | # you want CMake to locate. 36 | log) 37 | 38 | # Specifies libraries CMake should link to your target library. You 39 | # can link multiple libraries, such as libraries you define in this 40 | # build script, prebuilt third-party libraries, or system libraries. 41 | 42 | target_link_libraries( # Specifies the target library. 43 | alloc-lib 44 | ${log-lib} substrate fbjni) -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/Substrate/Buffer.hpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_BUFFER_HPP 23 | #define SUBSTRATE_BUFFER_HPP 24 | 25 | #include 26 | 27 | template 28 | _disused static _finline void MSWrite(uint8_t *&buffer, Type_ value) { 29 | *reinterpret_cast(buffer) = value; 30 | buffer += sizeof(Type_); 31 | } 32 | 33 | _disused static _finline void MSWrite(uint8_t *&buffer, uint8_t *data, size_t size) { 34 | memcpy(buffer, data, size); 35 | buffer += size; 36 | } 37 | 38 | #endif//SUBSTRATE_BUFFER_HPP 39 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/Substrate/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # For more information about using CMake with Android Studio, read the 2 | # documentation: https://d.android.com/studio/projects/add-native-code.html 3 | 4 | # Sets the minimum version of CMake required to build the native library. 5 | 6 | cmake_minimum_required(VERSION 3.6) 7 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ") 8 | 9 | # Creates and names a library, sets it as either STATIC 10 | # or SHARED, and provides the relative paths to its source code. 11 | # You can define multiple libraries, and CMake builds them for you. 12 | # Gradle automatically packages shared libraries with your APK. 13 | 14 | add_library( # Sets the name of the library. 15 | substrate 16 | STATIC 17 | hde64.c 18 | SubstrateDebug.cpp 19 | SubstrateHook.cpp 20 | SubstratePosixMemory.cpp 21 | ) 22 | 23 | # Searches for a specified prebuilt library and stores the path as a 24 | # variable. Because CMake includes system libraries in the search path by 25 | # default, you only need to specify the name of the public NDK library 26 | # you want to add. CMake verifies that the library exists before 27 | # completing its build. 28 | 29 | 30 | # Specifies libraries CMake should link to your target library. You 31 | # can link multiple libraries, such as libraries you define in this 32 | # build script, prebuilt third-party libraries, or system libraries. 33 | 34 | target_link_libraries( # Specifies the target library. 35 | substrate 36 | ) -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/Substrate/CydiaSubstrate.h: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_H_ 23 | #define SUBSTRATE_H_ 24 | 25 | #ifdef __APPLE__ 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | #include 30 | #ifdef __cplusplus 31 | } 32 | #endif 33 | 34 | #include 35 | #include 36 | #endif 37 | 38 | #include 39 | #include 40 | #include "math.h" 41 | #define _finline \ 42 | inline __attribute__((__always_inline__)) 43 | #define _disused \ 44 | __attribute__((__unused__)) 45 | 46 | #define _extern \ 47 | extern "C" __attribute__((__visibility__("default"))) 48 | 49 | #ifdef __cplusplus 50 | #define _default(value) = value 51 | #else 52 | #define _default(value) 53 | #endif 54 | 55 | #ifdef __cplusplus 56 | extern "C" { 57 | #endif 58 | 59 | bool MSHookProcess(pid_t pid, const char *library); 60 | 61 | typedef const void *MSImageRef; 62 | 63 | MSImageRef MSGetImageByName(const char *file); 64 | void *MSFindSymbol(MSImageRef image, const char *name); 65 | 66 | void MSHookFunction(void *symbol, void *replace, void **result); 67 | 68 | #ifdef __APPLE__ 69 | #ifdef __arm__ 70 | __attribute__((__deprecated__)) 71 | IMP MSHookMessage(Class _class, SEL sel, IMP imp, const char *prefix _default(NULL)); 72 | #endif 73 | void MSHookMessageEx(Class _class, SEL sel, IMP imp, IMP *result); 74 | #endif 75 | 76 | #ifdef SubstrateInternal 77 | typedef void *SubstrateAllocatorRef; 78 | typedef struct __SubstrateProcess *SubstrateProcessRef; 79 | typedef struct __SubstrateMemory *SubstrateMemoryRef; 80 | 81 | SubstrateProcessRef SubstrateProcessCreate(SubstrateAllocatorRef allocator, pid_t pid); 82 | void SubstrateProcessRelease(SubstrateProcessRef process); 83 | 84 | SubstrateMemoryRef SubstrateMemoryCreate(SubstrateAllocatorRef allocator, SubstrateProcessRef process, void *data, size_t size); 85 | void SubstrateMemoryRelease(SubstrateMemoryRef memory); 86 | #endif 87 | 88 | #ifdef __cplusplus 89 | } 90 | #endif 91 | 92 | #ifdef __cplusplus 93 | 94 | #ifdef SubstrateInternal 95 | struct SubstrateHookMemory { 96 | SubstrateMemoryRef handle_; 97 | 98 | SubstrateHookMemory(SubstrateProcessRef process, void *data, size_t size) : 99 | handle_(SubstrateMemoryCreate(NULL, NULL, data, size)) 100 | { 101 | } 102 | 103 | ~SubstrateHookMemory() { 104 | if (handle_ != NULL) 105 | SubstrateMemoryRelease(handle_); 106 | } 107 | }; 108 | #endif 109 | 110 | 111 | template 112 | static inline void MSHookFunction(Type_ *symbol, Type_ *replace, Type_ **result) { 113 | MSHookFunction( 114 | reinterpret_cast(symbol), 115 | reinterpret_cast(replace), 116 | reinterpret_cast(result) 117 | ); 118 | } 119 | 120 | template 121 | static inline void MSHookFunction(Type_ *symbol, Type_ *replace) { 122 | return MSHookFunction(symbol, replace, reinterpret_cast(NULL)); 123 | } 124 | 125 | template 126 | static inline void MSHookSymbol(Type_ *&value, const char *name, MSImageRef image = NULL) { 127 | value = reinterpret_cast(MSFindSymbol(image, name)); 128 | } 129 | 130 | template 131 | static inline void MSHookFunction(const char *name, Type_ *replace, Type_ **result = NULL) { 132 | Type_ *symbol; 133 | MSHookSymbol(symbol, name); 134 | return MSHookFunction(symbol, replace, result); 135 | } 136 | 137 | #endif 138 | 139 | #define MSHook(type, name, args...) \ 140 | _disused static type (*_ ## name)(args); \ 141 | static type $ ## name(args) 142 | 143 | #ifdef __cplusplus 144 | #define MSHake(name) \ 145 | &$ ## name, &_ ## name 146 | #else 147 | #define MSHake(name) \ 148 | &$ ## name, (void **) &_ ## name 149 | #endif 150 | 151 | 152 | #endif//SUBSTRATE_H_ 153 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/Substrate/SubstrateARM.hpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_ARM_HPP 23 | #define SUBSTRATE_ARM_HPP 24 | 25 | enum A$r { 26 | A$r0, A$r1, A$r2, A$r3, 27 | A$r4, A$r5, A$r6, A$r7, 28 | A$r8, A$r9, A$r10, A$r11, 29 | A$r12, A$r13, A$r14, A$r15, 30 | A$sp = A$r13, 31 | A$lr = A$r14, 32 | A$pc = A$r15 33 | }; 34 | 35 | enum A$c { 36 | A$eq, A$ne, A$cs, A$cc, 37 | A$mi, A$pl, A$vs, A$vc, 38 | A$hi, A$ls, A$ge, A$lt, 39 | A$gt, A$le, A$al, 40 | A$hs = A$cs, 41 | A$lo = A$cc 42 | }; 43 | 44 | #define A$mrs_rm_cpsr(rd) /* mrs rd, cpsr */ \ 45 | (0xe10f0000 | ((rd) << 12)) 46 | #define A$msr_cpsr_f_rm(rm) /* msr cpsr_f, rm */ \ 47 | (0xe128f000 | (rm)) 48 | #define A$ldr_rd_$rn_im$(rd, rn, im) /* ldr rd, [rn, #im] */ \ 49 | (0xe5100000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | labs(im)) 50 | #define A$str_rd_$rn_im$(rd, rn, im) /* sr rd, [rn, #im] */ \ 51 | (0xe5000000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | abs(im)) 52 | #define A$sub_rd_rn_$im(rd, rn, im) /* sub, rd, rn, #im */ \ 53 | (0xe2400000 | ((rn) << 16) | ((rd) << 12) | (im & 0xff)) 54 | #define A$blx_rm(rm) /* blx rm */ \ 55 | (0xe12fff30 | (rm)) 56 | #define A$mov_rd_rm(rd, rm) /* mov rd, rm */ \ 57 | (0xe1a00000 | ((rd) << 12) | (rm)) 58 | #define A$ldmia_sp$_$rs$(rs) /* ldmia sp!, {rs} */ \ 59 | (0xe8b00000 | (A$sp << 16) | (rs)) 60 | #define A$stmdb_sp$_$rs$(rs) /* stmdb sp!, {rs} */ \ 61 | (0xe9200000 | (A$sp << 16) | (rs)) 62 | #define A$stmia_sp$_$r0$ 0xe8ad0001 /* stmia sp!, {r0} */ 63 | #define A$bx_r0 0xe12fff10 /* bx r0 */ 64 | 65 | #endif//SUBSTRATE_ARM_HPP 66 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/Substrate/SubstrateDebug.cpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #include "SubstrateHook.h" 23 | #include "SubstrateDebug.hpp" 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | _extern bool MSDebug; 30 | bool MSDebug = false; 31 | 32 | static char _MSHexChar(uint8_t value) { 33 | return value < 0x20 || value >= 0x80 ? '.' : value; 34 | } 35 | 36 | #define HexWidth_ 16 37 | #define HexDepth_ 4 38 | 39 | void MSLogHexEx(const void *vdata, size_t size, size_t stride, const char *mark) { 40 | const uint8_t *data((const uint8_t *) vdata); 41 | 42 | size_t i(0), j; 43 | 44 | char d[256]; 45 | size_t b(0); 46 | d[0] = '\0'; 47 | 48 | while (i != size) { 49 | if (i % HexWidth_ == 0) { 50 | if (mark != NULL) 51 | b += sprintf(d + b, "\n[%s] ", mark); 52 | b += sprintf(d + b, "0x%.3zx:", i); 53 | } 54 | 55 | b += sprintf(d + b, " "); 56 | 57 | for (size_t q(0); q != stride; ++q) 58 | b += sprintf(d + b, "%.2x", data[i + stride - q - 1]); 59 | 60 | i += stride; 61 | 62 | for (size_t q(1); q != stride; ++q) 63 | b += sprintf(d + b, " "); 64 | 65 | if (i % HexDepth_ == 0) 66 | b += sprintf(d + b, " "); 67 | 68 | if (i % HexWidth_ == 0) { 69 | b += sprintf(d + b, " "); 70 | for (j = i - HexWidth_; j != i; ++j) 71 | b += sprintf(d + b, "%c", _MSHexChar(data[j])); 72 | 73 | lprintf("%s", d); 74 | b = 0; 75 | d[0] = '\0'; 76 | } 77 | } 78 | 79 | if (i % HexWidth_ != 0) { 80 | for (j = i % HexWidth_; j != HexWidth_; ++j) 81 | b += sprintf(d + b, " "); 82 | for (j = 0; j != (HexWidth_ - i % HexWidth_ + HexDepth_ - 1) / HexDepth_; ++j) 83 | b += sprintf(d + b, " "); 84 | b += sprintf(d + b, " "); 85 | for (j = i / HexWidth_ * HexWidth_; j != i; ++j) 86 | b += sprintf(d + b, "%c", _MSHexChar(data[j])); 87 | 88 | lprintf("%s", d); 89 | b = 0; 90 | d[0] = '\0'; 91 | } 92 | } 93 | 94 | void MSLogHex(const void *vdata, size_t size, const char *mark) { 95 | return MSLogHexEx(vdata, size, 1, mark); 96 | } 97 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/Substrate/SubstrateDebug.hpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_DEBUG_HPP 23 | #define SUBSTRATE_DEBUG_HPP 24 | 25 | #include "SubstrateLog.hpp" 26 | #define lprintf(format, ...) \ 27 | MSLog(MSLogLevelNotice, format, ## __VA_ARGS__) 28 | 29 | extern "C" bool MSDebug; 30 | void MSLogHexEx(const void *vdata, size_t size, size_t stride, const char *mark = 0); 31 | void MSLogHex(const void *vdata, size_t size, const char *mark = 0); 32 | 33 | #endif//SUBSTRATE_DEBUG_HPP 34 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/Substrate/SubstrateHook.h: -------------------------------------------------------------------------------- 1 | #ifndef __SUBSTRATEHOOK_H__ 2 | #define __SUBSTRATEHOOK_H__ 3 | 4 | 5 | #include 6 | 7 | #define _extern extern "C" __attribute__((__visibility__("default"))) 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | void MSHookFunction(void *symbol, void *replace, void **result); 14 | 15 | #ifdef __cplusplus 16 | } 17 | #endif 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/Substrate/SubstrateLog.hpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_LOG_HPP 23 | #define SUBSTRATE_LOG_HPP 24 | 25 | #if 0 26 | #include 27 | 28 | #define MSLog(level, format, ...) ((void)__android_log_print(level, "NNNN", format, __VA_ARGS__)) 29 | 30 | #define MSLogLevelNotice ANDROID_LOG_INFO 31 | #define MSLogLevelWarning ANDROID_LOG_WARN 32 | #define MSLogLevelError ANDROID_LOG_ERROR 33 | 34 | #else 35 | 36 | #define MSLog(level, format, ...) printf(format, __VA_ARGS__) 37 | 38 | #endif 39 | 40 | #endif//SUBSTRATE_LOG_HPP 41 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/Substrate/SubstratePosixMemory.cpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #define SubstrateInternal 23 | #include "CydiaSubstrate.h" 24 | #include "SubstrateLog.hpp" 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | extern "C" void __clear_cache (void *beg, void *end); 33 | 34 | struct __SubstrateMemory { 35 | void *address_; 36 | size_t width_; 37 | 38 | __SubstrateMemory(void *address, size_t width) : 39 | address_(address), 40 | width_(width) 41 | { 42 | } 43 | }; 44 | 45 | extern "C" SubstrateMemoryRef SubstrateMemoryCreate(SubstrateAllocatorRef allocator, SubstrateProcessRef process, void *data, size_t size) { 46 | if (allocator != NULL) { 47 | MSLog(MSLogLevelError, "MS:Error:allocator != %d", 0); 48 | return NULL; 49 | } 50 | 51 | if (size == 0) 52 | return NULL; 53 | 54 | long page(sysconf(_SC_PAGESIZE)); // Portable applications should employ sysconf(_SC_PAGESIZE) instead of getpagesize 55 | 56 | uintptr_t base(reinterpret_cast(data) / page * page); 57 | size_t width(((reinterpret_cast(data) + size - 1) / page + 1) * page - base); 58 | void *address(reinterpret_cast(base)); 59 | 60 | if (mprotect(address, width, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) { 61 | MSLog(MSLogLevelError, "MS:Error:mprotect() = %d", errno); 62 | return NULL; 63 | } 64 | 65 | return new __SubstrateMemory(address, width); 66 | } 67 | 68 | extern "C" void SubstrateMemoryRelease(SubstrateMemoryRef memory) { 69 | if (mprotect(memory->address_, memory->width_, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) 70 | MSLog(MSLogLevelError, "MS:Error:mprotect() = %d", errno); 71 | 72 | __clear_cache(reinterpret_cast(memory->address_), reinterpret_cast(memory->address_) + memory->width_); 73 | 74 | delete memory; 75 | } 76 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/Substrate/SubstrateX86.hpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_X86_HPP 23 | #define SUBSTRATE_X86_HPP 24 | 25 | #include "Buffer.hpp" 26 | 27 | #ifdef __LP64__ 28 | static const bool ia32 = false; 29 | #else 30 | static const bool ia32 = true; 31 | #endif 32 | 33 | enum I$r { 34 | I$rax, I$rcx, I$rdx, I$rbx, 35 | I$rsp, I$rbp, I$rsi, I$rdi, 36 | I$r8, I$r9, I$r10, I$r11, 37 | I$r12, I$r13, I$r14, I$r15, 38 | }; 39 | 40 | _disused static bool MSIs32BitOffset(uintptr_t target, uintptr_t source) { 41 | intptr_t offset(target - source); 42 | return int32_t(offset) == offset; 43 | } 44 | 45 | _disused static size_t MSSizeOfSkip() { 46 | return 5; 47 | } 48 | 49 | _disused static size_t MSSizeOfPushPointer(uintptr_t target) { 50 | return uint64_t(target) >> 32 == 0 ? 5 : 13; 51 | } 52 | 53 | _disused static size_t MSSizeOfPushPointer(void *target) { 54 | return MSSizeOfPushPointer(reinterpret_cast(target)); 55 | } 56 | 57 | _disused static size_t MSSizeOfJump(bool blind, uintptr_t target, uintptr_t source = 0) { 58 | if (ia32 || !blind && MSIs32BitOffset(target, source + 5)) 59 | return MSSizeOfSkip(); 60 | else 61 | return MSSizeOfPushPointer(target) + 1; 62 | } 63 | 64 | _disused static size_t MSSizeOfJump(uintptr_t target, uintptr_t source) { 65 | return MSSizeOfJump(false, target, source); 66 | } 67 | 68 | _disused static size_t MSSizeOfJump(uintptr_t target) { 69 | return MSSizeOfJump(true, target); 70 | } 71 | 72 | _disused static size_t MSSizeOfJump(void *target, void *source) { 73 | return MSSizeOfJump(reinterpret_cast(target), reinterpret_cast(source)); 74 | } 75 | 76 | _disused static size_t MSSizeOfJump(void *target) { 77 | return MSSizeOfJump(reinterpret_cast(target)); 78 | } 79 | 80 | _disused static void MSWriteSkip(uint8_t *¤t, ssize_t size) { 81 | MSWrite(current, 0xe9); 82 | MSWrite(current, size); 83 | } 84 | 85 | _disused static void MSPushPointer(uint8_t *¤t, uintptr_t target) { 86 | MSWrite(current, 0x68); 87 | MSWrite(current, target); 88 | 89 | if (uint32_t high = uint64_t(target) >> 32) { 90 | MSWrite(current, 0xc7); 91 | MSWrite(current, 0x44); 92 | MSWrite(current, 0x24); 93 | MSWrite(current, 0x04); 94 | MSWrite(current, high); 95 | } 96 | } 97 | 98 | _disused static void MSPushPointer(uint8_t *¤t, void *target) { 99 | return MSPushPointer(current, reinterpret_cast(target)); 100 | } 101 | 102 | _disused static void MSWriteCall(uint8_t *¤t, I$r target) { 103 | if (target >> 3 != 0) 104 | MSWrite(current, 0x40 | (target & 0x08) >> 3); 105 | MSWrite(current, 0xff); 106 | MSWrite(current, 0xd0 | target & 0x07); 107 | } 108 | 109 | _disused static void MSWriteCall(uint8_t *¤t, uintptr_t target) { 110 | uintptr_t source(reinterpret_cast(current)); 111 | 112 | if (ia32 || MSIs32BitOffset(target, source + 5)) { 113 | MSWrite(current, 0xe8); 114 | MSWrite(current, target - (source + 5)); 115 | } else { 116 | MSPushPointer(current, target); 117 | 118 | MSWrite(current, 0x83); 119 | MSWrite(current, 0xc4); 120 | MSWrite(current, 0x08); 121 | 122 | MSWrite(current, 0x67); 123 | MSWrite(current, 0xff); 124 | MSWrite(current, 0x54); 125 | MSWrite(current, 0x24); 126 | MSWrite(current, 0xf8); 127 | } 128 | } 129 | 130 | template 131 | _disused static void MSWriteCall(uint8_t *¤t, Type_ *target) { 132 | return MSWriteCall(current, reinterpret_cast(target)); 133 | } 134 | 135 | _disused static void MSWriteJump(uint8_t *¤t, uintptr_t target) { 136 | uintptr_t source(reinterpret_cast(current)); 137 | 138 | if (ia32 || MSIs32BitOffset(target, source + 5)) 139 | MSWriteSkip(current, target - (source + 5)); 140 | else { 141 | MSPushPointer(current, target); 142 | MSWrite(current, 0xc3); 143 | } 144 | } 145 | 146 | _disused static void MSWriteJump(uint8_t *¤t, void *target) { 147 | return MSWriteJump(current, reinterpret_cast(target)); 148 | } 149 | 150 | _disused static void MSWriteJump(uint8_t *¤t, I$r target) { 151 | if (target >> 3 != 0) 152 | MSWrite(current, 0x40 | (target & 0x08) >> 3); 153 | MSWrite(current, 0xff); 154 | MSWrite(current, 0xe0 | target & 0x07); 155 | } 156 | 157 | _disused static void MSWritePop(uint8_t *¤t, uint8_t target) { 158 | if (target >> 3 != 0) 159 | MSWrite(current, 0x40 | (target & 0x08) >> 3); 160 | MSWrite(current, 0x58 | target & 0x07); 161 | } 162 | 163 | _disused static size_t MSSizeOfPop(uint8_t target) { 164 | return target >> 3 != 0 ? 2 : 1; 165 | } 166 | 167 | _disused static void MSWritePush(uint8_t *¤t, I$r target) { 168 | if (target >> 3 != 0) 169 | MSWrite(current, 0x40 | (target & 0x08) >> 3); 170 | MSWrite(current, 0x50 | target & 0x07); 171 | } 172 | 173 | _disused static void MSWriteAdd(uint8_t *¤t, I$r target, uint8_t source) { 174 | MSWrite(current, 0x83); 175 | MSWrite(current, 0xc4 | target & 0x07); 176 | MSWrite(current, source); 177 | } 178 | 179 | _disused static void MSWriteSet64(uint8_t *¤t, I$r target, uintptr_t source) { 180 | MSWrite(current, 0x48 | (target & 0x08) >> 3 << 2); 181 | MSWrite(current, 0xb8 | target & 0x7); 182 | MSWrite(current, source); 183 | } 184 | 185 | template 186 | _disused static void MSWriteSet64(uint8_t *¤t, I$r target, Type_ *source) { 187 | return MSWriteSet64(current, target, reinterpret_cast(source)); 188 | } 189 | 190 | _disused static void MSWriteMove64(uint8_t *¤t, uint8_t source, uint8_t target) { 191 | MSWrite(current, 0x48 | (target & 0x08) >> 3 << 2 | (source & 0x08) >> 3); 192 | MSWrite(current, 0x8b); 193 | MSWrite(current, (target & 0x07) << 3 | source & 0x07); 194 | } 195 | 196 | _disused static size_t MSSizeOfMove64() { 197 | return 3; 198 | } 199 | 200 | #endif//SUBSTRATE_X86_HPP 201 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/Substrate/hde64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | * hde64.h: C/C++ header file 7 | * 8 | */ 9 | 10 | #ifndef _HDE64_H_ 11 | #define _HDE64_H_ 12 | 13 | /* stdint.h - C99 standard header 14 | * http://en.wikipedia.org/wiki/stdint.h 15 | * 16 | * if your compiler doesn't contain "stdint.h" header (for 17 | * example, Microsoft Visual C++), you can download file: 18 | * http://www.azillionmonkeys.com/qed/pstdint.h 19 | * and change next line to: 20 | * #include "pstdint.h" 21 | */ 22 | #include 23 | 24 | #define F_MODRM 0x00000001 25 | #define F_SIB 0x00000002 26 | #define F_IMM8 0x00000004 27 | #define F_IMM16 0x00000008 28 | #define F_IMM32 0x00000010 29 | #define F_IMM64 0x00000020 30 | #define F_DISP8 0x00000040 31 | #define F_DISP16 0x00000080 32 | #define F_DISP32 0x00000100 33 | #define F_RELATIVE 0x00000200 34 | #define F_ERROR 0x00001000 35 | #define F_ERROR_OPCODE 0x00002000 36 | #define F_ERROR_LENGTH 0x00004000 37 | #define F_ERROR_LOCK 0x00008000 38 | #define F_ERROR_OPERAND 0x00010000 39 | #define F_PREFIX_REPNZ 0x01000000 40 | #define F_PREFIX_REPX 0x02000000 41 | #define F_PREFIX_REP 0x03000000 42 | #define F_PREFIX_66 0x04000000 43 | #define F_PREFIX_67 0x08000000 44 | #define F_PREFIX_LOCK 0x10000000 45 | #define F_PREFIX_SEG 0x20000000 46 | #define F_PREFIX_REX 0x40000000 47 | #define F_PREFIX_ANY 0x7f000000 48 | 49 | #define PREFIX_SEGMENT_CS 0x2e 50 | #define PREFIX_SEGMENT_SS 0x36 51 | #define PREFIX_SEGMENT_DS 0x3e 52 | #define PREFIX_SEGMENT_ES 0x26 53 | #define PREFIX_SEGMENT_FS 0x64 54 | #define PREFIX_SEGMENT_GS 0x65 55 | #define PREFIX_LOCK 0xf0 56 | #define PREFIX_REPNZ 0xf2 57 | #define PREFIX_REPX 0xf3 58 | #define PREFIX_OPERAND_SIZE 0x66 59 | #define PREFIX_ADDRESS_SIZE 0x67 60 | 61 | #pragma pack(push,1) 62 | 63 | typedef struct { 64 | uint8_t len; 65 | uint8_t p_rep; 66 | uint8_t p_lock; 67 | uint8_t p_seg; 68 | uint8_t p_66; 69 | uint8_t p_67; 70 | uint8_t rex; 71 | uint8_t rex_w; 72 | uint8_t rex_r; 73 | uint8_t rex_x; 74 | uint8_t rex_b; 75 | uint8_t opcode; 76 | uint8_t opcode2; 77 | uint8_t modrm; 78 | uint8_t modrm_mod; 79 | uint8_t modrm_reg; 80 | uint8_t modrm_rm; 81 | uint8_t sib; 82 | uint8_t sib_scale; 83 | uint8_t sib_index; 84 | uint8_t sib_base; 85 | union { 86 | uint8_t imm8; 87 | uint16_t imm16; 88 | uint32_t imm32; 89 | uint64_t imm64; 90 | } imm; 91 | union { 92 | uint8_t disp8; 93 | uint16_t disp16; 94 | uint32_t disp32; 95 | } disp; 96 | uint32_t flags; 97 | } hde64s; 98 | 99 | #pragma pack(pop) 100 | 101 | #ifdef __cplusplus 102 | extern "C" { 103 | #endif 104 | 105 | /* __cdecl */ 106 | unsigned int hde64_disasm(const void *code, hde64s *hs); 107 | 108 | #ifdef __cplusplus 109 | } 110 | #endif 111 | 112 | #endif /* _HDE64_H_ */ 113 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/Substrate/table64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #define C_NONE 0x00 9 | #define C_MODRM 0x01 10 | #define C_IMM8 0x02 11 | #define C_IMM16 0x04 12 | #define C_IMM_P66 0x10 13 | #define C_REL8 0x20 14 | #define C_REL32 0x40 15 | #define C_GROUP 0x80 16 | #define C_ERROR 0xff 17 | 18 | #define PRE_ANY 0x00 19 | #define PRE_NONE 0x01 20 | #define PRE_F2 0x02 21 | #define PRE_F3 0x04 22 | #define PRE_66 0x08 23 | #define PRE_67 0x10 24 | #define PRE_LOCK 0x20 25 | #define PRE_SEG 0x40 26 | #define PRE_ALL 0xff 27 | 28 | #define DELTA_OPCODES 0x4a 29 | #define DELTA_FPU_REG 0xfd 30 | #define DELTA_FPU_MODRM 0x104 31 | #define DELTA_PREFIXES 0x13c 32 | #define DELTA_OP_LOCK_OK 0x1ae 33 | #define DELTA_OP2_LOCK_OK 0x1c6 34 | #define DELTA_OP_ONLY_MEM 0x1d8 35 | #define DELTA_OP2_ONLY_MEM 0x1e7 36 | 37 | unsigned char hde64_table[] = { 38 | 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5, 39 | 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1, 40 | 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea, 41 | 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0, 42 | 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab, 43 | 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92, 44 | 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90, 45 | 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b, 46 | 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, 47 | 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc, 48 | 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20, 49 | 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff, 50 | 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00, 51 | 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01, 52 | 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10, 53 | 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00, 54 | 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00, 55 | 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00, 56 | 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00, 57 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, 58 | 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00, 59 | 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40, 60 | 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43, 61 | 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, 62 | 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40, 63 | 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06, 64 | 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07, 65 | 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, 66 | 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10, 67 | 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00, 68 | 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb, 69 | 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff, 70 | 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09, 71 | 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff, 72 | 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08, 73 | 0x00,0xf0,0x02,0x00 74 | }; 75 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/alloctracker.h: -------------------------------------------------------------------------------- 1 | #ifndef _ALLOC_TRACKER_H 2 | #define _ALLOC_TRACKER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include "lock.h" 16 | #include "logger.h" 17 | 18 | using std::vector; 19 | using std::atomic; 20 | 21 | #define ALLOC_TRACKER_ART 1 22 | #define ALLOC_TRACKER_DVM 2 23 | 24 | 25 | static unsigned int LUCKY = 50; 26 | 27 | #ifdef HAVE_STDINT_H 28 | #include /* C99 */ 29 | typedef uint8_t u1; 30 | #else 31 | typedef unsigned char u1; 32 | #endif 33 | 34 | 35 | #define JNI_METHOD_DECL(ret_type, method_name) \ 36 | extern "C" JNIEXPORT ret_type JNICALL Java_##com_dodola_alloctrack##_##AllocTracker##_##method_name 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | class Class; 42 | 43 | struct SaveAllocationData { 44 | jbyteArray data; 45 | char dataFileName[128]; 46 | }; 47 | static int allocTrackerType; 48 | static void *libHandle = NULL; 49 | static atomic allocObjectCount(0); 50 | static size_t setAllocRecordMax = 8000; 51 | 52 | static bool needStopRecord = false; 53 | 54 | //lock 55 | static CMutex g_Lock; 56 | 57 | class Thread; 58 | 59 | class Object; 60 | 61 | __attribute__((always_inline)) inline uint8_t Read1(uintptr_t addr) { 62 | return *reinterpret_cast(addr); 63 | } 64 | 65 | __attribute__((always_inline)) inline uint16_t Read2(uintptr_t addr) { 66 | return *reinterpret_cast(addr); 67 | } 68 | 69 | __attribute__((always_inline)) inline uint32_t Read4(uintptr_t addr) { 70 | return *reinterpret_cast(addr); 71 | } 72 | 73 | __attribute__((always_inline)) inline uint64_t Read8(uintptr_t addr) { 74 | return *reinterpret_cast(addr); 75 | } 76 | 77 | __attribute__((always_inline)) inline uintptr_t AccessField( 78 | uintptr_t addr, 79 | uint32_t offset) { 80 | return addr + offset; 81 | } 82 | 83 | 84 | //////////////////////////////// 85 | //22 23 使用 后面整理 86 | static int *mallocRecordHead = NULL; 87 | static int *mallocRecordCount = NULL; 88 | static int *mallocRecordMax = NULL; 89 | 90 | static char *(*GetDescriptor)(Class *, std::string *) = NULL; 91 | 92 | static void (*artSetAllocTrackingEnable)(bool) = NULL; 93 | static jbyteArray (*artGetRecentAllocations)() = NULL; 94 | static void (*artEnvSetCheckJniEnabled)(bool) = NULL; 95 | static bool (*artVmSetCheckJniEnabled)(bool) = NULL; 96 | static bool (*artAllocMapClear)(void *) = NULL; 97 | static int artAPILevel = 0; 98 | 99 | // dump alloc log in art 100 | static void (*artDbgDumpRecentAllocations)() = NULL; 101 | static const char *storeDataDirectory; 102 | 103 | static bool newArtRecordAllocationDoing(Class *type, size_t byte_count); 104 | static bool newArtRecordAllocationDoing24(void *, Class *type, size_t byte_count); 105 | 106 | //RecordAllocation(Thread* self, 107 | //266 ObjPtr* obj, 108 | //267 size_t byte_count) 109 | static void (*oldArtRecordAllocation26)(void *_this, Thread *, void *obj, size_t); 110 | static void newArtRecordAllocation26(void *_this, Thread *self, void *obj, size_t byte_count) { 111 | if (needStopRecord) { 112 | return; 113 | } else { 114 | int objptr = Read4(reinterpret_cast(obj));//此处获取的其实是一个 ref 对象 115 | int classRef = Read4(objptr);//根据 ref 获取真实的对象地址 116 | newArtRecordAllocationDoing24(_this, reinterpret_cast(classRef), byte_count); 117 | oldArtRecordAllocation26(_this, self, obj, byte_count); 118 | } 119 | } 120 | 121 | 122 | static void (*oldArtRecordAllocation23)(Thread *, Class *, size_t); 123 | static void newArtRecordAllocation23(Thread *self, Class *type, size_t byte_count) { 124 | if (needStopRecord) { 125 | return; 126 | } else { 127 | if (newArtRecordAllocationDoing(type, byte_count)) { 128 | oldArtRecordAllocation23(self, type, byte_count); 129 | } 130 | } 131 | } 132 | static void (*oldArtRecordAllocation22)(Class *, size_t); 133 | static void newArtRecordAllocation22(Class *type, size_t byte_count) { 134 | if (needStopRecord) { 135 | return; 136 | } else { 137 | if (newArtRecordAllocationDoing(type, byte_count)) { 138 | oldArtRecordAllocation22(type, byte_count); 139 | } 140 | } 141 | } 142 | 143 | // the allocation tracker methods in Dalvik 144 | static void (*dvmEnableAllocTracker)() = NULL; 145 | static void (*dvmDisableAllocTracker)() = NULL; 146 | static bool (*dvmGenerateTrackedAllocationReport)(u1 **, size_t *) = NULL; 147 | static void (*dvmDumpTrackedAllocations)(bool) = NULL; 148 | static u1 *dvmAllocationData; 149 | static size_t dvmAllocationDataLen; 150 | static void startDvmAllocationTracker(); 151 | static void stopDvmAllocationTracker(); 152 | static void dumpDvmAllocationData(); 153 | static jbyteArray getDvmAllocationDataForJava(); 154 | 155 | static void startARTAllocationTracker(); 156 | static void stopARTAllocationTracker(); 157 | 158 | static jbyteArray getAllocationData(); 159 | static jbyteArray getARTAllocationData(); 160 | 161 | 162 | static void dumpAllocationDataInLog(); 163 | 164 | void hookFunc(); 165 | 166 | #ifdef __cplusplus 167 | } 168 | #endif 169 | 170 | #endif -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/dlopen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * @author : rrrfff@foxmail.com 4 | * https://github.com/rrrfff/ndk_dlopen 5 | * 6 | */ 7 | #include "dlopen.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define LOG_TAG "ndk_dlopen" 14 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) 15 | 16 | static volatile int SDK_INT = 0; 17 | static void *quick_on_stack_back; 18 | 19 | static union { 20 | void *generic_stub; 21 | 22 | void *(*quick_on_stack_replace)(const void *param1, const void *param2, 23 | const void *fake_trampoline, const void *called); 24 | } STUBS; 25 | 26 | void JNIEXPORT ndk_init(JNIEnv *env) { 27 | 28 | if (SDK_INT <= 0) { 29 | char sdk[PROP_VALUE_MAX]; 30 | __system_property_get("ro.build.version.sdk", sdk); 31 | SDK_INT = atoi(sdk); 32 | LOGI("SDK_INT = %d", SDK_INT); 33 | if (SDK_INT >= 24) { 34 | static __attribute__((__aligned__(PAGE_SIZE))) uint8_t __insns[PAGE_SIZE]; 35 | STUBS.generic_stub = __insns; 36 | mprotect(__insns, sizeof(__insns), PROT_READ | PROT_WRITE | PROT_EXEC); 37 | 38 | // we are currently hijacking "FatalError" as a fake system-call trampoline 39 | uintptr_t pv = (uintptr_t) (*env)->FatalError; 40 | uintptr_t pu = (pv | (PAGE_SIZE - 1)) + 1u; 41 | uintptr_t pd = (pv & ~(PAGE_SIZE - 1)); 42 | mprotect((void *) pd, pv + 8u >= pu ? PAGE_SIZE * 2u : PAGE_SIZE, 43 | PROT_READ | PROT_WRITE | PROT_EXEC); 44 | quick_on_stack_back = (void *) pv; 45 | 46 | #if defined(__i386__) 47 | /* 48 | DEFINE_FUNCTION art_quick_on_stack_replace 49 | movl 12(REG_VAR(esp)), REG_VAR(eax) 50 | movl (REG_VAR(esp)), REG_VAR(edx) 51 | movl REG_VAR(eax), (REG_VAR(esp)) 52 | movl REG_VAR(edx), 12(REG_VAR(esp)) 53 | pushl 16(REG_VAR(esp)) 54 | ret 55 | END_FUNCTION art_quick_on_stack_replace 56 | */ 57 | memcpy(__insns, "\x8B\x44\x24\x0C\x8B\x14\x24\x89\x04\x24\x89\x54\x24\x0C\xFF\x74\x24\x10\xC3", 19); 58 | /* 59 | DEFINE_FUNCTION art_quick_on_stack_back 60 | push 8(REG_VAR(esp)) 61 | ret 62 | END_FUNCTION art_quick_on_stack_back 63 | */ 64 | memcpy(quick_on_stack_back, "\xC3\xFF\x74\x24\x08\xC3", 6); 65 | quick_on_stack_back = (void *)(pv + 1); // inserts `ret` at first 66 | #elif defined(__x86_64__) 67 | // rdi, rsi, rdx, rcx, r8, r9 68 | /* 69 | 0x0000000000000000: 52 push rdx 70 | 0x0000000000000001: FF E1 jmp rcx 71 | */ 72 | memcpy(__insns, "\x52\xFF\xE1", 3); 73 | /* 74 | 0x0000000000000000: C3 ret 75 | */ 76 | memcpy(quick_on_stack_back, "\xC3", 1); 77 | #elif defined(__aarch64__) 78 | // x0~x7 79 | /* 80 | 0x0000000000000000: FD 7B BF A9 stp x29, x30, [sp, #-0x10]! 81 | 0x0000000000000004: FD 03 00 91 mov x29, sp 82 | 0x0000000000000008: FE 03 02 AA mov x30, x2 83 | 0x000000000000000C: 60 00 1F D6 br x3 84 | */ 85 | memcpy(__insns, "\xFD\x7B\xBF\xA9\xFD\x03\x00\x91\xFE\x03\x02\xAA\x60\x00\x1F\xD6", 16); 86 | /* 87 | 0x0000000000000000: FD 7B C1 A8 ldp x29, x30, [sp], #0x10 88 | 0x0000000000000004: C0 03 5F D6 ret 89 | */ 90 | memcpy(quick_on_stack_back, "\xFD\x7B\xC1\xA8\xC0\x03\x5F\xD6", 8); 91 | #elif defined(__arm__) 92 | // r0~r3 93 | /* 94 | 0x0000000000000000: 04 E0 2D E5 str lr, [sp, #-4]! 95 | 0x0000000000000004: 02 E0 A0 E1 mov lr, r2 96 | 0x0000000000000008: 13 FF 2F E1 bx r3 97 | */ 98 | memcpy(__insns, "\x04\xE0\x2D\xE5\x02\xE0\xA0\xE1\x13\xFF\x2F\xE1", 12); 99 | if ((pv & 1u) != 0u) { // Thumb 100 | /* 101 | 0x0000000000000000: 08 BC pop {r3} 102 | 0x0000000000000002: 18 47 bx r3 103 | */ 104 | memcpy((void *) (pv - 1), "\x08\xBC\x18\x47", 4); 105 | } else { 106 | /* 107 | 0x0000000000000000: 04 30 9D E4 pop {r3} 108 | 0x0000000000000004: 13 FF 2F E1 bx r3 109 | */ 110 | memcpy(quick_on_stack_back, "\x04\x30\x9D\xE4\x13\xFF\x2F\xE1", 8); 111 | } //if 112 | #else 113 | # error "not supported" 114 | #endif 115 | LOGI("init done! quick_on_stack_replace = %p, quick_on_stack_back = %p", 116 | STUBS.generic_stub, quick_on_stack_back); 117 | } //if 118 | } //if 119 | } 120 | 121 | void *JNIEXPORT ndk_dlopen(const char *filename, int flag) { 122 | if (SDK_INT >= 24) { 123 | #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || defined(__arm__) 124 | return STUBS.quick_on_stack_replace(filename, (void *) flag, 125 | quick_on_stack_back, dlopen); 126 | #else 127 | # error "not supported" 128 | #endif 129 | } //if 130 | 131 | return dlopen(filename, flag); 132 | } 133 | 134 | int JNIEXPORT ndk_dlclose(void *handle) { 135 | if (SDK_INT >= 24) { 136 | #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || defined(__arm__) 137 | return (int) STUBS.quick_on_stack_replace(handle, NULL, 138 | quick_on_stack_back, dlclose); 139 | #else 140 | # error "not supported" 141 | #endif 142 | } //if 143 | 144 | return dlclose(handle); 145 | } 146 | 147 | const char *JNIEXPORT ndk_dlerror(void) { 148 | if (SDK_INT >= 24) { 149 | #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || defined(__arm__) 150 | return STUBS.quick_on_stack_replace(NULL, NULL, 151 | quick_on_stack_back, dlerror); 152 | #else 153 | # error "not supported" 154 | #endif 155 | } //if 156 | 157 | return dlerror(); 158 | } 159 | 160 | void *JNIEXPORT ndk_dlsym(void *handle, const char *symbol) { 161 | if (SDK_INT >= 24) { 162 | #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || defined(__arm__) 163 | return STUBS.quick_on_stack_replace(handle, symbol, 164 | quick_on_stack_back, dlsym); 165 | 166 | #else 167 | # error "not supported" 168 | #endif 169 | } //if 170 | 171 | return dlsym(handle, symbol); 172 | } 173 | 174 | int JNIEXPORT ndk_dladdr(const void *ddr, Dl_info *info) { 175 | if (SDK_INT >= 24) { 176 | #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || defined(__arm__) 177 | return (int) STUBS.quick_on_stack_replace(ddr, info, 178 | quick_on_stack_back, dladdr); 179 | #else 180 | # error "not supported" 181 | #endif 182 | } //if 183 | 184 | return dladdr(ddr, info); 185 | } 186 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/dlopen.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * @author : rrrfff@foxmail.com 4 | * https://github.com/rrrfff/ndk_dlopen 5 | * 6 | */ 7 | #pragma once 8 | #include 9 | #include 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | void ndk_init(JNIEnv *env); 16 | void *ndk_dlopen(const char *filename, int flag); 17 | int ndk_dlclose(void *handle); 18 | const char *ndk_dlerror(void); 19 | void *ndk_dlsym(void *handle, const char *symbol); 20 | int ndk_dladdr(const void *ddr, Dl_info *info); 21 | 22 | #ifdef __cplusplus 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # For more information about using CMake with Android Studio, read the 2 | # documentation: https://d.android.com/studio/projects/add-native-code.html 3 | 4 | # Sets the minimum version of CMake required to build the native library. 5 | 6 | cmake_minimum_required(VERSION 3.6) 7 | 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DART_DEFAULT_GC_TYPE_IS_CMS -DDISABLE_CPUCAP -DDISABLE_XPLAT -fexceptions -DHAVE_POSIX_CLOCKS -Wno-unused -Wno-gnu-alignof-expression -Wno-missing-field-initializers -std=gnu++14 -fvisibility=hidden -fexceptions -Wextra -Wno-unused-parameter -Wno-format-security -Wno-unused-local-typedef") 9 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpack-struct=4 -g -Os -Wextra -DMUSEUM_NOOP_CHECK_MACROS -DMUSEUM_NOOP_THREAD_MUTATORS") 10 | 11 | # Creates and names a library, sets it as either STATIC 12 | # or SHARED, and provides the relative paths to its source code. 13 | # You can define multiple libraries, and CMake builds them for you. 14 | # Gradle automatically packages shared libraries with your APK. 15 | 16 | include_directories(.) 17 | add_library( # Sets the name of the library. 18 | fbjni 19 | STATIC 20 | lyra/lyra_exceptions.cpp 21 | lyra/lyra_breakpad.cpp 22 | lyra/cxa_throw.cpp 23 | lyra/lyra.cpp 24 | fbjni/ByteBuffer.cpp 25 | fbjni/fbjni.cpp 26 | # fbjni/OnLoad.cpp 27 | fbjni/ReadableByteChannel.cpp 28 | fbjni/detail/Environment.cpp 29 | fbjni/detail/Exceptions.cpp 30 | fbjni/detail/Hybrid.cpp 31 | fbjni/detail/References.cpp 32 | fbjni/detail/utf8.cpp 33 | ) 34 | 35 | 36 | # Searches for a specified prebuilt library and stores the path as a 37 | # variable. Because CMake includes system libraries in the search path by 38 | # default, you only need to specify the name of the public NDK library 39 | # you want to add. CMake verifies that the library exists before 40 | # completing its build. 41 | find_library( # Sets the name of the path variable. 42 | log-lib 43 | 44 | # Specifies the name of the NDK library that 45 | # you want CMake to locate. 46 | log) 47 | 48 | # Specifies libraries CMake should link to your target library. You 49 | # can link multiple libraries, such as libraries you define in this 50 | # build script, prebuilt third-party libraries, or system libraries. 51 | 52 | target_link_libraries( # Specifies the target library. 53 | fbjni 54 | 55 | # Links the target library to the log library 56 | # included in the NDK. 57 | ${log-lib}) -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/ByteBuffer.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | 19 | #include 20 | 21 | namespace facebook { 22 | namespace jni { 23 | 24 | namespace { 25 | local_ref createEmpty() { 26 | static auto cls = JByteBuffer::javaClassStatic(); 27 | static auto meth = cls->getStaticMethod("allocateDirect"); 28 | return meth(cls, 0); 29 | } 30 | } 31 | 32 | void JBuffer::rewind() const { 33 | static auto meth = javaClassStatic()->getMethod()>("rewind"); 34 | meth(self()); 35 | } 36 | 37 | local_ref JByteBuffer::wrapBytes(uint8_t* data, size_t size) { 38 | // env->NewDirectByteBuffer requires that size is positive. Android's 39 | // dalvik returns an invalid result and Android's art aborts if size == 0. 40 | // Workaround this by using a slow path through Java in that case. 41 | if (!size) { 42 | return createEmpty(); 43 | } 44 | auto res = adopt_local(static_cast(Environment::current()->NewDirectByteBuffer(data, size))); 45 | FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); 46 | if (!res) { 47 | throw std::runtime_error("Direct byte buffers are unsupported."); 48 | } 49 | return res; 50 | } 51 | 52 | uint8_t* JByteBuffer::getDirectBytes() const { 53 | if (!self()) { 54 | throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException"); 55 | } 56 | void* bytes = Environment::current()->GetDirectBufferAddress(self()); 57 | FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); 58 | if (!bytes) { 59 | throw std::runtime_error( 60 | isDirect() ? 61 | "Attempt to get direct bytes of non-direct byte buffer." : 62 | "Error getting direct bytes of byte buffer."); 63 | } 64 | return static_cast(bytes); 65 | } 66 | 67 | size_t JByteBuffer::getDirectSize() const { 68 | if (!self()) { 69 | throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException"); 70 | } 71 | int size = Environment::current()->GetDirectBufferCapacity(self()); 72 | FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); 73 | if (size < 0) { 74 | throw std::runtime_error( 75 | isDirect() ? 76 | "Attempt to get direct size of non-direct byte buffer." : 77 | "Error getting direct size of byte buffer."); 78 | } 79 | return static_cast(size); 80 | } 81 | 82 | bool JByteBuffer::isDirect() const { 83 | static auto meth = javaClassStatic()->getMethod("isDirect"); 84 | return meth(self()); 85 | } 86 | 87 | }} 88 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/ByteBuffer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | namespace facebook { 22 | namespace jni { 23 | 24 | class JBuffer : public JavaClass { 25 | public: 26 | static constexpr const char* kJavaDescriptor = "Ljava/nio/Buffer;"; 27 | 28 | void rewind() const; 29 | }; 30 | 31 | // JNI's NIO support has some awkward preconditions and error reporting. This 32 | // class provides much more user-friendly access. 33 | class JByteBuffer : public JavaClass { 34 | public: 35 | static constexpr const char* kJavaDescriptor = "Ljava/nio/ByteBuffer;"; 36 | 37 | static local_ref wrapBytes(uint8_t* data, size_t size); 38 | 39 | bool isDirect() const; 40 | 41 | uint8_t* getDirectBytes() const; 42 | size_t getDirectSize() const; 43 | }; 44 | 45 | }} 46 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/Context.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | namespace facebook { 23 | namespace jni { 24 | 25 | class AContext : public JavaClass { 26 | public: 27 | static constexpr const char* kJavaDescriptor = "Landroid/content/Context;"; 28 | 29 | // Define a method that calls into the represented Java class 30 | local_ref getCacheDir() { 31 | static const auto method = getClass()->getMethod("getCacheDir"); 32 | return method(self()); 33 | } 34 | 35 | local_ref getFilesDir() { 36 | static const auto method = getClass()->getMethod("getFilesDir"); 37 | return method(self()); 38 | } 39 | }; 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/File.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | namespace facebook { 22 | namespace jni { 23 | 24 | class JFile : public JavaClass { 25 | public: 26 | static constexpr const char* kJavaDescriptor = "Ljava/io/File;"; 27 | 28 | // Define a method that calls into the represented Java class 29 | std::string getAbsolutePath() { 30 | static const auto method = getClass()->getMethod("getAbsolutePath"); 31 | return method(self())->toStdString(); 32 | } 33 | 34 | }; 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/JThread.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | namespace facebook { 23 | namespace jni { 24 | 25 | class JThread : public JavaClass { 26 | public: 27 | static constexpr const char* kJavaDescriptor = "Ljava/lang/Thread;"; 28 | 29 | void start() { 30 | static const auto method = javaClassStatic()->getMethod("start"); 31 | method(self()); 32 | } 33 | 34 | void join() { 35 | static const auto method = javaClassStatic()->getMethod("join"); 36 | method(self()); 37 | } 38 | 39 | static local_ref create(std::function&& runnable) { 40 | auto jrunnable = JNativeRunnable::newObjectCxxArgs(std::move(runnable)); 41 | return newInstance(static_ref_cast(jrunnable)); 42 | } 43 | 44 | static local_ref create(std::function&& runnable, std::string&& name) { 45 | auto jrunnable = JNativeRunnable::newObjectCxxArgs(std::move(runnable)); 46 | return newInstance(static_ref_cast(jrunnable), make_jstring(std::move(name))); 47 | } 48 | 49 | static local_ref getCurrent() { 50 | static const auto method = javaClassStatic()->getStaticMethod()>("currentThread"); 51 | return method(javaClassStatic()); 52 | } 53 | 54 | int getPriority() { 55 | static const auto method = getClass()->getMethod("getPriority"); 56 | return method(self()); 57 | } 58 | 59 | void setPriority(int priority) { 60 | static const auto method = getClass()->getMethod("setPriority"); 61 | method(self(), priority); 62 | } 63 | }; 64 | 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/NativeRunnable.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | #include 22 | 23 | namespace facebook { 24 | namespace jni { 25 | 26 | struct JRunnable : public JavaClass { 27 | static auto constexpr kJavaDescriptor = "Ljava/lang/Runnable;"; 28 | }; 29 | 30 | struct JNativeRunnable : public HybridClass { 31 | public: 32 | static auto constexpr kJavaDescriptor = "Lcom/facebook/jni/NativeRunnable;"; 33 | 34 | JNativeRunnable(std::function&& runnable) : runnable_(std::move(runnable)) {} 35 | 36 | static void OnLoad() { 37 | registerHybrid({ 38 | makeNativeMethod("run", JNativeRunnable::run), 39 | }); 40 | } 41 | 42 | void run() { 43 | runnable_(); 44 | } 45 | 46 | private: 47 | std::function runnable_; 48 | }; 49 | 50 | 51 | } // namespace jni 52 | } // namespace facebook 53 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/OnLoad.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | using namespace facebook::jni; 21 | 22 | JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { 23 | return facebook::jni::initialize(vm, [] { 24 | HybridDataOnLoad(); 25 | JNativeRunnable::OnLoad(); 26 | ThreadScope::OnLoad(); 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/ReadableByteChannel.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | 19 | namespace facebook { 20 | namespace jni { 21 | 22 | int JReadableByteChannel::read(alias_ref dest) const { 23 | if (!self()) { 24 | throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException"); 25 | } 26 | static auto method = javaClassStatic()->getMethod)>("read"); 27 | return method(self(), dest); 28 | } 29 | 30 | }} 31 | 32 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/ReadableByteChannel.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | namespace facebook { 23 | namespace jni { 24 | 25 | class JReadableByteChannel : public JavaClass { 26 | public: 27 | static constexpr const char* kJavaDescriptor = "Ljava/nio/channels/ReadableByteChannel;"; 28 | 29 | int read(alias_ref dest) const; 30 | }; 31 | 32 | }} 33 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/Boxed.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "CoreClasses.h" 20 | 21 | namespace facebook { 22 | namespace jni { 23 | 24 | namespace detail { 25 | template 26 | struct JPrimitive : JavaClass { 27 | using typename JavaClass::javaobject; 28 | using JavaClass::javaClassStatic; 29 | static local_ref valueOf(jprim val) { 30 | static const auto cls = javaClassStatic(); 31 | static const auto method = 32 | cls->template getStaticMethod("valueOf"); 33 | return method(cls, val); 34 | } 35 | jprim value() const { 36 | static const auto method = 37 | javaClassStatic()->template getMethod(T::kValueMethod); 38 | return method(this->self()); 39 | } 40 | }; 41 | 42 | } // namespace detail 43 | 44 | 45 | #define DEFINE_BOXED_PRIMITIVE(LITTLE, BIG) \ 46 | struct J ## BIG : detail::JPrimitive { \ 47 | static auto constexpr kJavaDescriptor = "Ljava/lang/" #BIG ";"; \ 48 | static auto constexpr kValueMethod = #LITTLE "Value"; \ 49 | j ## LITTLE LITTLE ## Value() const { \ 50 | return value(); \ 51 | } \ 52 | }; \ 53 | inline local_ref autobox(j ## LITTLE val) { \ 54 | return J ## BIG::valueOf(val); \ 55 | } 56 | 57 | DEFINE_BOXED_PRIMITIVE(boolean, Boolean) 58 | DEFINE_BOXED_PRIMITIVE(byte, Byte) 59 | DEFINE_BOXED_PRIMITIVE(char, Character) 60 | DEFINE_BOXED_PRIMITIVE(short, Short) 61 | DEFINE_BOXED_PRIMITIVE(int, Integer) 62 | DEFINE_BOXED_PRIMITIVE(long, Long) 63 | DEFINE_BOXED_PRIMITIVE(float, Float) 64 | DEFINE_BOXED_PRIMITIVE(double, Double) 65 | 66 | #undef DEFINE_BOXED_PRIMITIVE 67 | 68 | template 69 | inline typename std::enable_if< 70 | std::is_same::value && !std::is_same::value, 71 | local_ref 72 | >::type autobox(T val) { 73 | return JLong::valueOf(val); 74 | } 75 | 76 | struct JVoid : public jni::JavaClass { 77 | static auto constexpr kJavaDescriptor = "Ljava/lang/Void;"; 78 | }; 79 | 80 | inline local_ref autobox(alias_ref val) { 81 | return make_local(val); 82 | } 83 | 84 | }} 85 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/Common.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** @file Common.h 18 | * 19 | * Defining the stuff that don't deserve headers of their own... 20 | */ 21 | 22 | #pragma once 23 | 24 | #include 25 | 26 | #include 27 | 28 | #ifdef FBJNI_DEBUG_REFS 29 | # ifdef __ANDROID__ 30 | # include 31 | # else 32 | # include 33 | # endif 34 | #endif 35 | 36 | // If a pending JNI Java exception is found, wraps it in a JniException object and throws it as 37 | // a C++ exception. 38 | #define FACEBOOK_JNI_THROW_PENDING_EXCEPTION() \ 39 | ::facebook::jni::throwPendingJniExceptionAsCppException() 40 | 41 | // If the condition is true, throws a JniException object, which wraps the pending JNI Java 42 | // exception if any. If no pending exception is found, throws a JniException object that wraps a 43 | // RuntimeException throwable.  44 | #define FACEBOOK_JNI_THROW_EXCEPTION_IF(CONDITION) \ 45 | ::facebook::jni::throwCppExceptionIf(CONDITION) 46 | 47 | /// @cond INTERNAL 48 | 49 | namespace facebook { 50 | namespace jni { 51 | 52 | void throwPendingJniExceptionAsCppException(); 53 | void throwCppExceptionIf(bool condition); 54 | 55 | [[noreturn]] void throwNewJavaException(jthrowable); 56 | [[noreturn]] void throwNewJavaException(const char* throwableName, const char* msg); 57 | template 58 | [[noreturn]] void throwNewJavaException(const char* throwableName, const char* fmt, Args... args); 59 | 60 | 61 | /** 62 | * This needs to be called at library load time, typically in your JNI_OnLoad method. 63 | * 64 | * The intended use is to return the result of initialize() directly 65 | * from JNI_OnLoad and to do nothing else there. Library specific 66 | * initialization code should go in the function passed to initialize 67 | * (which can be, and probably should be, a C++ lambda). This approach 68 | * provides correct error handling and translation errors during 69 | * initialization into Java exceptions when appropriate. 70 | * 71 | * Failure to call this will cause your code to crash in a remarkably 72 | * unhelpful way (typically a segfault) while trying to handle an exception 73 | * which occurs later. 74 | */ 75 | jint initialize(JavaVM*, std::function&&) noexcept; 76 | 77 | namespace internal { 78 | 79 | // Define to get extremely verbose logging of references and to enable reference stats 80 | #ifdef FBJNI_DEBUG_REFS 81 | template 82 | inline void dbglog(const char* msg, Args... args) { 83 | # ifdef __ANDROID__ 84 | __android_log_print(ANDROID_LOG_VERBOSE, "fbjni_dbg", msg, args...); 85 | # else 86 | std::fprintf(stderr, msg, args...); 87 | # endif 88 | } 89 | 90 | #else 91 | 92 | template 93 | inline void dbglog(const char*, Args...) { 94 | } 95 | 96 | #endif 97 | 98 | }}} 99 | 100 | /// @endcond 101 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/Environment.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | #include 19 | #include 20 | #include 21 | 22 | 23 | namespace facebook { 24 | namespace jni { 25 | 26 | // Keeps a thread-local reference to the current thread's JNIEnv. 27 | struct Environment { 28 | // Throws a std::runtime_error if this thread isn't attached to the JVM 29 | // TODO(T6594868) Benchmark against raw JNI access 30 | static JNIEnv* current(); 31 | static void initialize(JavaVM* vm); 32 | 33 | // There are subtle issues with calling the next functions directly. It is 34 | // much better to always use a ThreadScope to manage attaching/detaching for 35 | // you. 36 | static JNIEnv* ensureCurrentThreadIsAttached(); 37 | }; 38 | 39 | namespace detail { 40 | 41 | // This will return null the thread isn't attached to the VM, or if 42 | // fbjni has never been initialized with a VM at all. You probably 43 | // shouldn't be using this. 44 | JNIEnv* currentOrNull(); 45 | 46 | /** 47 | * If there's thread-local data, it's a pointer to one of these. The 48 | * instance is a member of JniEnvCacher or ThreadScope, and lives on 49 | * the stack. 50 | */ 51 | struct TLData { 52 | // This is modified only by JniEnvCacher, and is guaranteed to be 53 | // valid if set, and refer to an env which originated from a JNI 54 | // call into C++. 55 | JNIEnv* env; 56 | // This is modified only by ThreadScope, and is set only if an 57 | // instance of ThreadScope which attached is on the stack. 58 | bool attached; 59 | }; 60 | 61 | /** 62 | * RAII object which manages a cached JNIEnv* value. A Value is only 63 | * cached if it is guaranteed safe, which means when C++ is called 64 | * from a registered fbjni function. 65 | */ 66 | class JniEnvCacher { 67 | public: 68 | JniEnvCacher(JNIEnv* env); 69 | JniEnvCacher(JniEnvCacher&) = delete; 70 | JniEnvCacher(JniEnvCacher&&) = default; 71 | JniEnvCacher& operator=(JniEnvCacher&) = delete; 72 | JniEnvCacher& operator=(JniEnvCacher&&) = delete; 73 | ~JniEnvCacher(); 74 | 75 | private: 76 | // If this flag is set, then, this object needs to clear the cache. 77 | bool thisCached_; 78 | 79 | // The thread local pointer may point here. 80 | detail::TLData data_; 81 | }; 82 | 83 | } 84 | 85 | /** 86 | * RAII Object that attaches a thread to the JVM. Failing to detach from a thread before it 87 | * exits will cause a crash, as will calling Detach an extra time, and this guard class helps 88 | * keep that straight. In addition, it remembers whether it performed the attach or not, so it 89 | * is safe to nest it with itself or with non-fbjni code that manages the attachment correctly. 90 | * 91 | * Potential concerns: 92 | * - Attaching to the JVM is fast (~100us on MotoG), but ideally you would attach while the 93 | * app is not busy. 94 | * - Having a thread detach at arbitrary points is not safe in Dalvik; you need to be sure that 95 | * there is no Java code on the current stack or you run the risk of a crash like: 96 | * ERROR: detaching thread with interp frames (count=18) 97 | * (More detail at https://groups.google.com/forum/#!topic/android-ndk/2H8z5grNqjo) 98 | * ThreadScope won't do a detach if the thread was already attached before the guard is 99 | * instantiated, but there's probably some usage that could trip this up. 100 | * - Newly attached C++ threads only get the bootstrap class loader -- i.e. java language 101 | * classes, not any of our application's classes. This will be different behavior than threads 102 | * that were initiated on the Java side. A workaround is to pass a global reference for a 103 | * class or instance to the new thread; this bypasses the need for the class loader. 104 | * (See http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html#attach_current_thread) 105 | * If you need access to the application's classes, you can use ThreadScope::WithClassLoader. 106 | * - If fbjni has never been initialized, there will be no JavaVM object to attach with. 107 | * In that case, a std::runtime_error will be thrown. This is only likely to happen in a 108 | * standalone C++ application, or if Environment::initialize is not used. 109 | */ 110 | class ThreadScope { 111 | public: 112 | ThreadScope(); 113 | ThreadScope(ThreadScope&) = delete; 114 | ThreadScope(ThreadScope&&) = default; 115 | ThreadScope& operator=(ThreadScope&) = delete; 116 | ThreadScope& operator=(ThreadScope&&) = delete; 117 | ~ThreadScope(); 118 | 119 | /** 120 | * This runs the closure in a scope with fbjni's classloader. This should be 121 | * the same classloader as the rest of the application and thus anything 122 | * running in the closure will have access to the same classes as in a normal 123 | * java-create thread. 124 | */ 125 | static void WithClassLoader(std::function&& runnable); 126 | 127 | static void OnLoad(); 128 | 129 | private: 130 | // If this flag is set, then this object needs to detach. 131 | bool thisAttached_; 132 | 133 | // The thread local pointer may point here. 134 | detail::TLData data_; 135 | }; 136 | 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/Exceptions.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * @file Exceptions.h 19 | * 20 | * After invoking a JNI function that can throw a Java exception, the macro 21 | * @ref FACEBOOK_JNI_THROW_PENDING_EXCEPTION() or @ref FACEBOOK_JNI_THROW_EXCEPTION_IF() 22 | * should be invoked. 23 | * 24 | * IMPORTANT! IMPORTANT! IMPORTANT! IMPORTANT! IMPORTANT! IMPORTANT! IMPORTANT! IMPORTANT! 25 | * To use these methods you MUST call initExceptionHelpers() when your library is loaded. 26 | */ 27 | 28 | #pragma once 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | #include "Common.h" 37 | #include "References.h" 38 | #include "CoreClasses.h" 39 | 40 | #if defined(__ANDROID__) && defined(__ARM_ARCH_5TE__) && !defined(FBJNI_NO_EXCEPTION_PTR) 41 | // ARMv5 NDK does not support exception_ptr so we cannot use that when building for it. 42 | #define FBJNI_NO_EXCEPTION_PTR 43 | #endif 44 | 45 | namespace facebook { 46 | namespace jni { 47 | 48 | class JThrowable; 49 | 50 | class JCppException : public JavaClass { 51 | public: 52 | static auto constexpr kJavaDescriptor = "Lcom/facebook/jni/CppException;"; 53 | 54 | static local_ref create(const char* str) { 55 | return newInstance(make_jstring(str)); 56 | } 57 | 58 | static local_ref create(const std::exception& ex) { 59 | return newInstance(make_jstring(ex.what())); 60 | } 61 | }; 62 | 63 | // JniException //////////////////////////////////////////////////////////////////////////////////// 64 | 65 | /** 66 | * This class wraps a Java exception into a C++ exception; if the exception is routed back 67 | * to the Java side, it can be unwrapped and just look like a pure Java interaction. The class 68 | * is resilient to errors while creating the exception, falling back to some pre-allocated 69 | * exceptions if a new one cannot be allocated or populated. 70 | * 71 | * Note: the what() method of this class is not thread-safe (t6900503). 72 | */ 73 | class JniException : public std::exception { 74 | public: 75 | JniException(); 76 | ~JniException(); 77 | 78 | explicit JniException(alias_ref throwable); 79 | 80 | JniException(JniException &&rhs); 81 | 82 | JniException(const JniException &other); 83 | 84 | local_ref getThrowable() const noexcept; 85 | 86 | virtual const char* what() const noexcept; 87 | 88 | void setJavaException() const noexcept; 89 | 90 | private: 91 | global_ref throwable_; 92 | mutable std::string what_; 93 | mutable bool isMessageExtracted_; 94 | const static std::string kExceptionMessageFailure_; 95 | 96 | void populateWhat() const noexcept; 97 | }; 98 | 99 | // Exception throwing & translating functions ////////////////////////////////////////////////////// 100 | 101 | // Functions that throw C++ exceptions 102 | 103 | static const int kMaxExceptionMessageBufferSize = 512; 104 | 105 | // These methods are the preferred way to throw a Java exception from 106 | // a C++ function. They create and throw a C++ exception which wraps 107 | // a Java exception, so the C++ flow is interrupted. Then, when 108 | // translatePendingCppExceptionToJavaException is called at the 109 | // topmost level of the native stack, the wrapped Java exception is 110 | // thrown to the java caller. 111 | template 112 | [[noreturn]] void throwNewJavaException(const char* throwableName, const char* fmt, Args... args) { 113 | int msgSize = snprintf(nullptr, 0, fmt, args...); 114 | 115 | char *msg = (char*) alloca(msgSize + 1); 116 | snprintf(msg, kMaxExceptionMessageBufferSize, fmt, args...); 117 | throwNewJavaException(throwableName, msg); 118 | } 119 | 120 | // Identifies any pending C++ exception and throws it as a Java exception. If the exception can't 121 | // be thrown, it aborts the program. 122 | void translatePendingCppExceptionToJavaException(); 123 | 124 | #ifndef FBJNI_NO_EXCEPTION_PTR 125 | local_ref getJavaExceptionForCppException(std::exception_ptr ptr); 126 | #endif 127 | 128 | /*** 129 | * The stack returned may include build ids. It may be beneficial to 130 | * call lyra::setLibraryIdentifierFunction before calling this if 131 | * build ids are desirable. 132 | */ 133 | local_ref getJavaExceptionForCppBackTrace(); 134 | 135 | local_ref getJavaExceptionForCppBackTrace(const char* msg); 136 | 137 | // For convenience, some exception names in java.lang are available here. 138 | const char* const gJavaLangIllegalArgumentException = "java/lang/IllegalArgumentException"; 139 | 140 | }} 141 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/Hybrid.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | 19 | namespace facebook { 20 | namespace jni { 21 | 22 | namespace detail { 23 | 24 | local_ref HybridData::create() { 25 | return newInstance(); 26 | } 27 | 28 | } 29 | 30 | namespace { 31 | void deleteNative(alias_ref, jlong ptr) { 32 | delete reinterpret_cast(ptr); 33 | } 34 | } 35 | 36 | void HybridDataOnLoad() { 37 | registerNatives("com/facebook/jni/HybridData$Destructor", { 38 | makeNativeMethod("deleteNative", deleteNative), 39 | }); 40 | } 41 | 42 | }} 43 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/Iterator-inl.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | namespace facebook { 20 | namespace jni { 21 | 22 | namespace detail { 23 | 24 | template 25 | struct IteratorHelper : public JavaClass> { 26 | constexpr static auto kJavaDescriptor = "Lcom/facebook/jni/IteratorHelper;"; 27 | 28 | typedef local_ref value_type; 29 | typedef ptrdiff_t difference_type; 30 | typedef value_type* pointer; 31 | typedef value_type& reference; 32 | typedef std::forward_iterator_tag iterator_category; 33 | 34 | typedef JavaClass> JavaBase_; 35 | 36 | bool hasNext() const { 37 | static auto hasNextMethod = 38 | JavaBase_::javaClassStatic()->template getMethod("hasNext"); 39 | return hasNextMethod(JavaBase_::self()); 40 | } 41 | 42 | value_type next() { 43 | static auto elementField = 44 | JavaBase_::javaClassStatic()->template getField("mElement"); 45 | return dynamic_ref_cast>(JavaBase_::getFieldValue(elementField)); 46 | } 47 | 48 | static void reset(value_type& v) { 49 | v.reset(); 50 | } 51 | }; 52 | 53 | template 54 | struct MapIteratorHelper : public JavaClass> { 55 | constexpr static auto kJavaDescriptor = "Lcom/facebook/jni/MapIteratorHelper;"; 56 | 57 | typedef std::pair, local_ref> value_type; 58 | 59 | typedef JavaClass> JavaBase_; 60 | 61 | bool hasNext() const { 62 | static auto hasNextMethod = 63 | JavaBase_::javaClassStatic()->template getMethod("hasNext"); 64 | return hasNextMethod(JavaBase_::self()); 65 | } 66 | 67 | value_type next() { 68 | static auto keyField = JavaBase_::javaClassStatic()->template getField("mKey"); 69 | static auto valueField = JavaBase_::javaClassStatic()->template getField("mValue"); 70 | return std::make_pair(dynamic_ref_cast(JavaBase_::getFieldValue(keyField)), 71 | dynamic_ref_cast(JavaBase_::getFieldValue(valueField))); 72 | } 73 | 74 | static void reset(value_type& v) { 75 | v.first.reset(); 76 | v.second.reset(); 77 | } 78 | }; 79 | 80 | template 81 | class Iterator { 82 | public: 83 | typedef typename T::value_type value_type; 84 | typedef ptrdiff_t difference_type; 85 | typedef value_type* pointer; 86 | typedef value_type& reference; 87 | typedef std::input_iterator_tag iterator_category; 88 | 89 | // begin ctor 90 | Iterator(global_ref&& helper) 91 | : helper_(std::move(helper)) 92 | , i_(-1) { 93 | ++(*this); 94 | } 95 | 96 | // end ctor 97 | Iterator() 98 | : i_(-1) {} 99 | 100 | bool operator==(const Iterator& it) const { return i_ == it.i_; } 101 | bool operator!=(const Iterator& it) const { return !(*this == it); } 102 | const value_type& operator*() const { assert(i_ != -1); return entry_; } 103 | const value_type* operator->() const { assert(i_ != -1); return &entry_; } 104 | Iterator& operator++() { // preincrement 105 | bool hasNext = helper_->hasNext(); 106 | if (hasNext) { 107 | ++i_; 108 | entry_ = helper_->next(); 109 | } else { 110 | i_ = -1; 111 | helper_->reset(entry_); 112 | } 113 | return *this; 114 | } 115 | Iterator operator++(int) { // postincrement 116 | Iterator ret; 117 | ret.i_ = i_; 118 | ret.entry_ = std::move(entry_); 119 | ++(*this); 120 | return ret; 121 | } 122 | 123 | global_ref helper_; 124 | // set to -1 at end 125 | std::ptrdiff_t i_; 126 | value_type entry_; 127 | }; 128 | 129 | } 130 | 131 | template 132 | struct JIterator::Iterator : public detail::Iterator> { 133 | using detail::Iterator>::Iterator; 134 | }; 135 | 136 | template 137 | typename JIterator::Iterator JIterator::begin() const { 138 | static auto ctor = detail::IteratorHelper::javaClassStatic()-> 139 | template getConstructor::javaobject( 140 | typename JIterator::javaobject)>(); 141 | return Iterator( 142 | make_global( 143 | detail::IteratorHelper::javaClassStatic()->newObject(ctor, this->self()))); 144 | } 145 | 146 | template 147 | typename JIterator::Iterator JIterator::end() const { 148 | return Iterator(); 149 | } 150 | 151 | template 152 | struct JIterable::Iterator : public detail::Iterator> { 153 | using detail::Iterator>::Iterator; 154 | }; 155 | 156 | template 157 | typename JIterable::Iterator JIterable::begin() const { 158 | static auto ctor = detail::IteratorHelper::javaClassStatic()-> 159 | template getConstructor::javaobject( 160 | typename JIterable::javaobject)>(); 161 | return Iterator( 162 | make_global( 163 | detail::IteratorHelper::javaClassStatic()->newObject(ctor, this->self()))); 164 | } 165 | 166 | template 167 | typename JIterable::Iterator JIterable::end() const { 168 | return Iterator(); 169 | } 170 | 171 | template 172 | size_t JCollection::size() const { 173 | static auto sizeMethod = 174 | JCollection::javaClassStatic()->template getMethod("size"); 175 | return sizeMethod(this->self()); 176 | } 177 | 178 | template 179 | struct JMap::Iterator : public detail::Iterator> { 180 | using detail::Iterator>::Iterator; 181 | }; 182 | 183 | template 184 | size_t JMap::size() const { 185 | static auto sizeMethod = 186 | JMap::javaClassStatic()->template getMethod("size"); 187 | return sizeMethod(this->self()); 188 | } 189 | 190 | template 191 | typename JMap::Iterator JMap::begin() const { 192 | static auto ctor = detail::MapIteratorHelper::javaClassStatic()-> 193 | template getConstructor::javaobject( 194 | typename JMap::javaobject)>(); 195 | return Iterator( 196 | make_global( 197 | detail::MapIteratorHelper::javaClassStatic()->newObject(ctor, this->self()))); 198 | } 199 | 200 | template 201 | typename JMap::Iterator JMap::end() const { 202 | return Iterator(); 203 | } 204 | 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/Iterator.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "CoreClasses.h" 20 | 21 | namespace facebook { 22 | namespace jni { 23 | 24 | /** 25 | * JavaClass which represents a reference to a java.util.Iterator instance. It 26 | * provides begin()/end() methods to provide C++-style iteration over the 27 | * underlying collection. The class has a template parameter for the element 28 | * type, which defaults to jobject. For example: 29 | * 30 | * alias_ref::javaobject> my_iter = ...; 31 | * 32 | * In the simplest case, it can be used just as alias_ref::javaobject>, 33 | * for example in a method declaration. 34 | */ 35 | template 36 | struct JIterator : JavaClass> { 37 | constexpr static auto kJavaDescriptor = "Ljava/util/Iterator;"; 38 | 39 | struct Iterator; 40 | 41 | /** 42 | * To iterate: 43 | * 44 | * for (const auto& element : *jiter) { ... } 45 | * 46 | * The JIterator iterator value_type is local_ref, containing a reference 47 | * to an element instance. 48 | * 49 | * If the Iterator returns objects whch are not convertible to the given 50 | * element type, iteration will throw a java ClassCastException. 51 | * 52 | * For example, to convert an iterator over a collection of java strings to 53 | * an std::vector of std::strings: 54 | * 55 | * std::vector vs; 56 | * for (const auto& elem : *jiter) { 57 | * vs.push_back(elem->toStdString()); 58 | * } 59 | * 60 | * Or if you prefer using std algorithms: 61 | * 62 | * std::vector vs; 63 | * std::transform(jiter->begin(), jiter->end(), std::back_inserter(vs), 64 | * [](const local_ref& elem) { return elem->toStdString(); }); 65 | * 66 | * The iterator is a InputIterator. 67 | */ 68 | Iterator begin() const; 69 | Iterator end() const; 70 | }; 71 | 72 | /** 73 | * Similar to JIterator, except this represents any object which implements the 74 | * java.lang.Iterable interface. It will create the Java Iterator as a part of 75 | * begin(). 76 | */ 77 | template 78 | struct JIterable : JavaClass> { 79 | constexpr static auto kJavaDescriptor = "Ljava/lang/Iterable;"; 80 | 81 | struct Iterator; 82 | 83 | Iterator begin() const; 84 | Iterator end() const; 85 | }; 86 | 87 | /** 88 | * JavaClass types which represent Collection, List, and Set are also provided. 89 | * These preserve the Java class heirarchy. 90 | */ 91 | template 92 | struct JCollection : JavaClass, JIterable> { 93 | constexpr static auto kJavaDescriptor = "Ljava/util/Collection;"; 94 | 95 | /** 96 | * Returns the number of elements in the collection. 97 | */ 98 | size_t size() const; 99 | }; 100 | 101 | template 102 | struct JList : JavaClass, JCollection> { 103 | constexpr static auto kJavaDescriptor = "Ljava/util/List;"; 104 | }; 105 | 106 | template 107 | struct JSet : JavaClass, JCollection> { 108 | constexpr static auto kJavaDescriptor = "Ljava/util/Set;"; 109 | }; 110 | 111 | /** 112 | * JavaClass which represents a reference to a java.util.Map instance. It adds 113 | * wrappers around Java methods, including begin()/end() methods to provide 114 | * C++-style iteration over the Java Map. The class has template parameters 115 | * for the key and value types, which default to jobject. For example: 116 | * 117 | * alias_ref::javaobject> my_map = ...; 118 | * 119 | * In the simplest case, it can be used just as alias_ref::javaobject>, 120 | * for example in a method declaration. 121 | */ 122 | template 123 | struct JMap : JavaClass> { 124 | constexpr static auto kJavaDescriptor = "Ljava/util/Map;"; 125 | 126 | struct Iterator; 127 | 128 | /** 129 | * Returns the number of pairs in the map. 130 | */ 131 | size_t size() const; 132 | 133 | /** 134 | * To iterate over the Map: 135 | * 136 | * for (const auto& entry : *jmap) { ... } 137 | * 138 | * The JMap iterator value_type is std::pair, local_ref> 139 | * containing references to key and value instances. 140 | * 141 | * If the Map contains objects whch are not convertible to the given key and 142 | * value types, iteration will throw a java ClassCastException. 143 | * 144 | * The iterator is a InputIterator. 145 | */ 146 | Iterator begin() const; 147 | Iterator end() const; 148 | }; 149 | 150 | } 151 | } 152 | 153 | #include "Iterator-inl.h" 154 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/JWeakReference.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2004-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "CoreClasses.h" 20 | 21 | namespace facebook { 22 | namespace jni { 23 | 24 | /** 25 | * Wrap Java's WeakReference instead of using JNI WeakGlobalRefs. 26 | * A WeakGlobalRef can yield a strong reference even after the object has been 27 | * finalized. See comment in the djinni library. 28 | * https://github.com/dropbox/djinni/blob/master/support-lib/jni/djinni_support.hpp 29 | */ 30 | template 31 | class JWeakReference : public JavaClass> { 32 | 33 | typedef JavaClass> JavaBase_; 34 | 35 | public: 36 | static constexpr const char* kJavaDescriptor = "Ljava/lang/ref/WeakReference;"; 37 | 38 | static local_ref> newInstance(alias_ref object) { 39 | return JavaBase_::newInstance(static_ref_cast(object)); 40 | } 41 | 42 | local_ref get() const { 43 | static const auto method = JavaBase_::javaClassStatic()->template getMethod("get"); 44 | return static_ref_cast(method(JavaBase_::self())); 45 | } 46 | }; 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/Log.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** @file ALog.h 18 | * 19 | * Very simple (android only) logging. Define LOG_TAG to enable the macros. 20 | */ 21 | 22 | #pragma once 23 | 24 | #ifdef __ANDROID__ 25 | 26 | #include 27 | 28 | namespace facebook { 29 | namespace jni { 30 | namespace log_ { 31 | // the weird name of this namespace is to avoid a conflict with the 32 | // function named log. 33 | 34 | inline void loge(const char* tag, const char* msg) noexcept { 35 | __android_log_write(ANDROID_LOG_ERROR, tag, msg); 36 | } 37 | 38 | template 39 | inline void loge(const char* tag, const char* msg, ARGS... args) noexcept { 40 | __android_log_print(ANDROID_LOG_ERROR, tag, msg, args...); 41 | } 42 | 43 | inline void logf(const char* tag, const char* msg) noexcept { 44 | __android_log_write(ANDROID_LOG_FATAL, tag, msg); 45 | } 46 | 47 | template 48 | inline void logf(const char* tag, const char* msg, ARGS... args) noexcept { 49 | __android_log_print(ANDROID_LOG_FATAL, tag, msg, args...); 50 | } 51 | 52 | template 53 | [[noreturn]] 54 | inline void logassert(const char* tag, const char* msg, ARGS... args) noexcept { 55 | __android_log_assert(0, tag, msg, args...); 56 | } 57 | 58 | 59 | #ifdef LOG_TAG 60 | # define FBJNI_LOGE(...) ::facebook::jni::log_::loge(LOG_TAG, __VA_ARGS__) 61 | # define FBJNI_LOGF(...) ::facebook::jni::log_::logf(LOG_TAG, __VA_ARGS__) 62 | # define FBJNI_ASSERT(cond) do { if (!(cond)) ::facebook::jni::log_::logassert(LOG_TAG, "%s", #cond); } while(0) 63 | #else 64 | # define FBJNI_LOGE(...) ::facebook::jni::log_::loge("log", __VA_ARGS__) 65 | # define FBJNI_LOGF(...) ::facebook::jni::log_::logf("log", __VA_ARGS__) 66 | # define FBJNI_ASSERT(cond) do { if (!(cond)) ::facebook::jni::log_::logassert("log", "%s", #cond); } while(0) 67 | #endif 68 | 69 | }}} 70 | 71 | #else 72 | #include 73 | 74 | # define FBJNI_LOGE(...) ((void)0) 75 | # define FBJNI_LOGF(...) (abort()) 76 | # define FBJNI_ASSERT(cond) ((void)0) 77 | #endif 78 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/Meta-forward.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | namespace facebook { 20 | namespace jni { 21 | 22 | template 23 | class JMethod; 24 | template 25 | class JStaticMethod; 26 | template 27 | class JNonvirtualMethod; 28 | template 29 | struct JConstructor; 30 | template 31 | class JField; 32 | template 33 | class JStaticField; 34 | 35 | /// Type traits for Java types (currently providing Java type descriptors) 36 | template 37 | struct jtype_traits; 38 | 39 | /// Type traits for Java methods (currently providing Java type descriptors) 40 | template 41 | struct jmethod_traits; 42 | 43 | }} 44 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/MetaConvert.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2004-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | #include "Common.h" 22 | #include "References.h" 23 | 24 | namespace facebook { 25 | namespace jni { 26 | 27 | namespace detail { 28 | 29 | // In order to avoid potentially filling the jni locals table, 30 | // temporary objects (right now, this is just jstrings) need to be 31 | // released. This is done by returning a holder which autoconverts to 32 | // jstring. 33 | template 34 | inline T callToJni(T&& t) { 35 | return t; 36 | } 37 | 38 | template 39 | inline JniType callToJni(local_ref&& sref) { 40 | return sref.get(); 41 | } 42 | 43 | // Normally, pass through types unmolested. 44 | template 45 | struct Convert { 46 | typedef T jniType; 47 | static jniType fromJni(jniType t) { 48 | return t; 49 | } 50 | static jniType toJniRet(jniType t) { 51 | return t; 52 | } 53 | static jniType toCall(jniType t) { 54 | return t; 55 | } 56 | }; 57 | 58 | // This is needed for return conversion 59 | template <> 60 | struct Convert { 61 | typedef void jniType; 62 | }; 63 | 64 | // jboolean is an unsigned char, not a bool. Allow it to work either way. 65 | template<> 66 | struct Convert { 67 | typedef jboolean jniType; 68 | static bool fromJni(jniType t) { 69 | return t; 70 | } 71 | static jniType toJniRet(bool t) { 72 | return t; 73 | } 74 | static jniType toCall(bool t) { 75 | return t; 76 | } 77 | }; 78 | 79 | // Sometimes (64-bit Android) jlong is "long long", but int64_t is "long". 80 | // Allow int64_t to work as jlong. 81 | template 82 | struct Convert::value && !std::is_same::value 85 | >::type> { 86 | typedef jlong jniType; 87 | static int64_t fromJni(jniType t) { 88 | return t; 89 | } 90 | static jniType toJniRet(int64_t t) { 91 | return t; 92 | } 93 | static jniType toCall(int64_t t) { 94 | return t; 95 | } 96 | }; 97 | 98 | // convert to alias_ref from T 99 | template 100 | struct Convert> { 101 | typedef JniType jniType; 102 | static alias_ref fromJni(jniType t) { 103 | return wrap_alias(t); 104 | } 105 | static jniType toJniRet(alias_ref t) { 106 | return t.get(); 107 | } 108 | static jniType toCall(alias_ref t) { 109 | return t.get(); 110 | } 111 | }; 112 | 113 | // convert return from local_ref 114 | template 115 | struct Convert> { 116 | typedef JniType jniType; 117 | // No automatic synthesis of local_ref 118 | static jniType toJniRet(local_ref t) { 119 | return t.release(); 120 | } 121 | static jniType toCall(local_ref t) { 122 | return t.get(); 123 | } 124 | }; 125 | 126 | // convert return from global_ref 127 | template 128 | struct Convert> { 129 | typedef JniType jniType; 130 | // No automatic synthesis of global_ref 131 | static jniType toJniRet(global_ref&& t) { 132 | // If this gets called, ownership the global_ref was passed in here. (It's 133 | // probably a copy of a persistent global_ref made when a function was 134 | // declared to return a global_ref, but it could moved out or otherwise not 135 | // referenced elsewhere. Doesn't matter.) Either way, the only safe way 136 | // to return it is to make a local_ref, release it, and return the 137 | // underlying local jobject. 138 | auto ret = make_local(t); 139 | return ret.release(); 140 | } 141 | static jniType toJniRet(const global_ref& t) { 142 | // If this gets called, the function was declared to return const&. We 143 | // have a ref to a global_ref whose lifetime will exceed this call, so we 144 | // can just get the underlying jobject and return it to java without 145 | // needing to make a local_ref. 146 | return t.get(); 147 | } 148 | static jniType toCall(global_ref t) { 149 | return t.get(); 150 | } 151 | }; 152 | 153 | template struct jni_sig_from_cxx_t; 154 | template 155 | struct jni_sig_from_cxx_t { 156 | using JniRet = typename Convert::type>::jniType; 157 | using JniSig = JniRet(typename Convert::type>::jniType...); 158 | }; 159 | 160 | template 161 | using jni_sig_from_cxx = typename jni_sig_from_cxx_t::JniSig; 162 | 163 | } // namespace detail 164 | 165 | template 166 | struct jmethod_traits_from_cxx : jmethod_traits> { 167 | }; 168 | 169 | }} 170 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/ReferenceAllocators-inl.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "Environment.h" 24 | 25 | namespace facebook { 26 | namespace jni { 27 | 28 | /// @cond INTERNAL 29 | namespace internal { 30 | 31 | // Statistics mostly provided for test (only updated if FBJNI_DEBUG_REFS is defined) 32 | struct ReferenceStats { 33 | std::atomic_uint locals_created, globals_created, weaks_created, 34 | locals_deleted, globals_deleted, weaks_deleted; 35 | 36 | void reset() noexcept; 37 | }; 38 | 39 | extern ReferenceStats g_reference_stats; 40 | } 41 | /// @endcond 42 | 43 | 44 | // LocalReferenceAllocator ///////////////////////////////////////////////////////////////////////// 45 | 46 | inline jobject LocalReferenceAllocator::newReference(jobject original) const { 47 | internal::dbglog("Local new: %p", original); 48 | #ifdef FBJNI_DEBUG_REFS 49 | ++internal::g_reference_stats.locals_created; 50 | #endif 51 | auto ref = Environment::current()->NewLocalRef(original); 52 | FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); 53 | return ref; 54 | } 55 | 56 | inline void LocalReferenceAllocator::deleteReference(jobject reference) const noexcept { 57 | internal::dbglog("Local release: %p", reference); 58 | 59 | if (reference) { 60 | #ifdef FBJNI_DEBUG_REFS 61 | ++internal::g_reference_stats.locals_deleted; 62 | #endif 63 | assert(verifyReference(reference)); 64 | Environment::current()->DeleteLocalRef(reference); 65 | } 66 | } 67 | 68 | inline bool LocalReferenceAllocator::verifyReference(jobject reference) const noexcept { 69 | return isObjectRefType(reference, JNILocalRefType); 70 | } 71 | 72 | 73 | // GlobalReferenceAllocator //////////////////////////////////////////////////////////////////////// 74 | 75 | inline jobject GlobalReferenceAllocator::newReference(jobject original) const { 76 | internal::dbglog("Global new: %p", original); 77 | #ifdef FBJNI_DEBUG_REFS 78 | ++internal::g_reference_stats.globals_created; 79 | #endif 80 | auto ref = Environment::current()->NewGlobalRef(original); 81 | FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); 82 | return ref; 83 | } 84 | 85 | inline void GlobalReferenceAllocator::deleteReference(jobject reference) const noexcept { 86 | internal::dbglog("Global release: %p", reference); 87 | 88 | if (reference) { 89 | #ifdef FBJNI_DEBUG_REFS 90 | ++internal::g_reference_stats.globals_deleted; 91 | #endif 92 | assert(verifyReference(reference)); 93 | Environment::current()->DeleteGlobalRef(reference); 94 | } 95 | } 96 | 97 | inline bool GlobalReferenceAllocator::verifyReference(jobject reference) const noexcept { 98 | return isObjectRefType(reference, JNIGlobalRefType); 99 | } 100 | 101 | 102 | // WeakGlobalReferenceAllocator //////////////////////////////////////////////////////////////////// 103 | 104 | inline jobject WeakGlobalReferenceAllocator::newReference(jobject original) const { 105 | internal::dbglog("Weak global new: %p", original); 106 | #ifdef FBJNI_DEBUG_REFS 107 | ++internal::g_reference_stats.weaks_created; 108 | #endif 109 | auto ref = Environment::current()->NewWeakGlobalRef(original); 110 | FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); 111 | return ref; 112 | } 113 | 114 | inline void WeakGlobalReferenceAllocator::deleteReference(jobject reference) const noexcept { 115 | internal::dbglog("Weak Global release: %p", reference); 116 | 117 | if (reference) { 118 | #ifdef FBJNI_DEBUG_REFS 119 | ++internal::g_reference_stats.weaks_deleted; 120 | #endif 121 | assert(verifyReference(reference)); 122 | Environment::current()->DeleteWeakGlobalRef(reference); 123 | } 124 | } 125 | 126 | inline bool WeakGlobalReferenceAllocator::verifyReference(jobject reference) const noexcept { 127 | return isObjectRefType(reference, JNIWeakGlobalRefType); 128 | } 129 | 130 | }} 131 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/ReferenceAllocators.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * @file ReferenceAllocators.h 19 | * 20 | * Reference allocators are used to create and delete various classes of JNI references (local, 21 | * global, and weak global). 22 | */ 23 | 24 | #pragma once 25 | 26 | #include "Common.h" 27 | 28 | namespace facebook { namespace jni { 29 | 30 | /// Allocator that handles local references 31 | class LocalReferenceAllocator { 32 | public: 33 | jobject newReference(jobject original) const; 34 | void deleteReference(jobject reference) const noexcept; 35 | bool verifyReference(jobject reference) const noexcept; 36 | }; 37 | 38 | /// Allocator that handles global references 39 | class GlobalReferenceAllocator { 40 | public: 41 | jobject newReference(jobject original) const; 42 | void deleteReference(jobject reference) const noexcept; 43 | bool verifyReference(jobject reference) const noexcept; 44 | }; 45 | 46 | /// Allocator that handles weak global references 47 | class WeakGlobalReferenceAllocator { 48 | public: 49 | jobject newReference(jobject original) const; 50 | void deleteReference(jobject reference) const noexcept; 51 | bool verifyReference(jobject reference) const noexcept; 52 | }; 53 | 54 | /** 55 | * @return Helper based on GetObjectRefType. Since this isn't defined 56 | * on all versions of Java or Android, if the type can't be 57 | * determined, this returns true. If reference is nullptr, returns 58 | * true. 59 | */ 60 | bool isObjectRefType(jobject reference, jobjectRefType refType); 61 | 62 | }} 63 | 64 | #include "ReferenceAllocators-inl.h" 65 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/References-forward.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "ReferenceAllocators.h" 20 | 21 | namespace facebook { 22 | namespace jni { 23 | 24 | template 25 | class JObjectWrapper; 26 | 27 | namespace detail { 28 | struct JObjectBase { 29 | jobject get() const noexcept; 30 | void set(jobject reference) noexcept; 31 | jobject this_; 32 | }; 33 | 34 | // RefReprType maps a type to the representation used by fbjni smart references. 35 | template 36 | struct RefReprType; 37 | 38 | template 39 | struct JavaObjectType; 40 | 41 | template 42 | struct ReprAccess; 43 | } 44 | 45 | // Given T, either a jobject-like type or a JavaClass-derived type, ReprType 46 | // is the corresponding JavaClass-derived type and JniType is the 47 | // jobject-like type. 48 | template 49 | using ReprType = typename detail::RefReprType::type; 50 | 51 | template 52 | using JniType = typename detail::JavaObjectType::type; 53 | 54 | template 55 | class base_owned_ref; 56 | 57 | template 58 | class basic_strong_ref; 59 | 60 | template 61 | class weak_ref; 62 | 63 | template 64 | class alias_ref; 65 | 66 | /// A smart unique reference owning a local JNI reference 67 | template 68 | using local_ref = basic_strong_ref; 69 | 70 | /// A smart unique reference owning a global JNI reference 71 | template 72 | using global_ref = basic_strong_ref; 73 | 74 | }} // namespace facebook::jni 75 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/References.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "References.h" 18 | 19 | namespace facebook { 20 | namespace jni { 21 | 22 | JniLocalScope::JniLocalScope(JNIEnv* env, jint capacity) 23 | : env_(env) { 24 | hasFrame_ = false; 25 | auto pushResult = env->PushLocalFrame(capacity); 26 | FACEBOOK_JNI_THROW_EXCEPTION_IF(pushResult < 0); 27 | hasFrame_ = true; 28 | } 29 | 30 | JniLocalScope::~JniLocalScope() { 31 | if (hasFrame_) { 32 | env_->PopLocalFrame(nullptr); 33 | } 34 | } 35 | 36 | namespace { 37 | 38 | #ifdef __ANDROID__ 39 | 40 | int32_t getAndroidApiLevel() { 41 | // This is called from the static local initializer in 42 | // isObjectRefType(), and creating fbjni references can call 43 | // isObjectRefType(). So, to avoid recursively entering the block 44 | // where the static is initialized (which is undefined behavior), we 45 | // avoid using standard fbjni references here. 46 | 47 | JNIEnv* env = Environment::current(); 48 | jclass cls = detail::findClass(env, "android/os/Build$VERSION"); 49 | jfieldID field = env->GetStaticFieldID(cls, "SDK_INT", 50 | jtype_traits::descriptor().c_str()); 51 | if (!field) { 52 | env->DeleteLocalRef(cls); 53 | } 54 | FACEBOOK_JNI_THROW_EXCEPTION_IF(!field); 55 | int32_t ret = env->GetStaticIntField(cls, field); 56 | env->DeleteLocalRef(cls); 57 | return ret; 58 | } 59 | 60 | bool doesGetObjectRefTypeWork() { 61 | auto level = getAndroidApiLevel(); 62 | return level >= 14; 63 | } 64 | 65 | #else 66 | 67 | bool doesGetObjectRefTypeWork() { 68 | auto jni_version = Environment::current()->GetVersion(); 69 | return jni_version >= JNI_VERSION_1_6; 70 | } 71 | 72 | #endif 73 | 74 | } 75 | 76 | bool isObjectRefType(jobject reference, jobjectRefType refType) { 77 | // null-check first so that we short-circuit during (safe) global 78 | // constructors, where we won't have an Environment::current() yet 79 | if (!reference) { 80 | return true; 81 | } 82 | 83 | static bool getObjectRefTypeWorks = doesGetObjectRefTypeWork(); 84 | 85 | return 86 | !getObjectRefTypeWorks || 87 | Environment::current()->GetObjectRefType(reference) == refType; 88 | } 89 | 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/Registration-inl.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "Exceptions.h" 20 | #include "Hybrid.h" 21 | 22 | namespace facebook { 23 | namespace jni { 24 | 25 | namespace detail { 26 | 27 | #ifdef __i386__ 28 | // X86 ABI forces 16 byte stack allignment on calls. Unfortunately 29 | // sometimes Dalvik chooses not to obey the ABI: 30 | // - https://code.google.com/p/android/issues/detail?id=61012 31 | // - https://android.googlesource.com/platform/ndk/+/81696d2%5E!/ 32 | // Therefore, we tell the compiler to re-align the stack on entry 33 | // to our JNI functions. 34 | #define JNI_ENTRY_POINT __attribute__((force_align_arg_pointer)) 35 | #else 36 | #define JNI_ENTRY_POINT 37 | #endif 38 | 39 | template 40 | struct CreateDefault { 41 | static R create() { 42 | return R{}; 43 | } 44 | }; 45 | 46 | template <> 47 | struct CreateDefault { 48 | static void create() {} 49 | }; 50 | 51 | template 52 | using Converter = Convert::type>; 53 | 54 | template 55 | struct WrapForVoidReturn { 56 | static typename Converter::jniType call(Args&&... args) { 57 | return Converter::toJniRet(func(std::forward(args)...)); 58 | } 59 | }; 60 | 61 | template 62 | struct WrapForVoidReturn { 63 | static void call(Args&&... args) { 64 | func(std::forward(args)...); 65 | } 66 | }; 67 | 68 | // registration wrapper for legacy JNI-style functions 69 | template 70 | struct BareJniWrapper { 71 | JNI_ENTRY_POINT static R call(JNIEnv* env, jobject obj, Args... args) { 72 | detail::JniEnvCacher jec(env); 73 | try { 74 | return (*func)(env, static_cast>(obj), args...); 75 | } catch (...) { 76 | translatePendingCppExceptionToJavaException(); 77 | return CreateDefault::create(); 78 | } 79 | } 80 | }; 81 | 82 | // registration wrappers for functions, with autoconversion of arguments. 83 | template 84 | struct FunctionWrapper { 85 | using jniRet = typename Converter::jniType; 86 | JNI_ENTRY_POINT static jniRet call(JNIEnv* env, jobject obj, typename Converter::jniType... args) { 87 | detail::JniEnvCacher jec(env); 88 | try { 89 | return WrapForVoidReturn, Args...>::call( 90 | static_cast>(obj), Converter::fromJni(args)...); 91 | } catch (...) { 92 | translatePendingCppExceptionToJavaException(); 93 | return CreateDefault::create(); 94 | } 95 | } 96 | }; 97 | 98 | // registration wrappers for non-static methods, with autoconvertion of arguments. 99 | template 100 | struct MethodWrapper { 101 | using jhybrid = typename C::jhybridobject; 102 | static R dispatch(alias_ref ref, Args&&... args) { 103 | try { 104 | // This is usually a noop, but if the hybrid object is a 105 | // base class of other classes which register JNI methods, 106 | // this will get the right type for the registered method. 107 | auto cobj = static_cast(ref->cthis()); 108 | return (cobj->*method)(std::forward(args)...); 109 | } catch (const std::exception& ex) { 110 | C::mapException(ex); 111 | throw; 112 | } 113 | } 114 | 115 | JNI_ENTRY_POINT static typename Converter::jniType call( 116 | JNIEnv* env, jobject obj, typename Converter::jniType... args) { 117 | return FunctionWrapper, Args&&...), dispatch, jhybrid, R, Args...>::call(env, obj, args...); 118 | } 119 | }; 120 | 121 | template 122 | inline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(JNIEnv*, C, Args... args)) { 123 | // This intentionally erases the real type; JNI will do it anyway 124 | return reinterpret_cast(&(BareJniWrapper::call)); 125 | } 126 | 127 | template 128 | inline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(alias_ref, Args... args)) { 129 | // This intentionally erases the real type; JNI will do it anyway 130 | return reinterpret_cast(&(FunctionWrapper::call)); 131 | } 132 | 133 | template 134 | inline NativeMethodWrapper* exceptionWrapJNIMethod(R (C::*method0)(Args... args)) { 135 | (void)method0; 136 | // This intentionally erases the real type; JNI will do it anyway 137 | return reinterpret_cast(&(MethodWrapper::call)); 138 | } 139 | 140 | template 141 | inline std::string makeDescriptor(R (*)(JNIEnv*, C, Args... args)) { 142 | return jmethod_traits::descriptor(); 143 | } 144 | 145 | template 146 | inline std::string makeDescriptor(R (*)(alias_ref, Args... args)) { 147 | return jmethod_traits_from_cxx::descriptor(); 148 | } 149 | 150 | template 151 | inline std::string makeDescriptor(R (C::*)(Args... args)) { 152 | return jmethod_traits_from_cxx::descriptor(); 153 | } 154 | 155 | template 156 | template 157 | JNI_ENTRY_POINT R CriticalMethod::call(alias_ref, Args... args) noexcept { 158 | static_assert( 159 | IsJniPrimitive() || std::is_void(), 160 | "Critical Native Methods may only return primitive JNI types, or void."); 161 | static_assert( 162 | AreJniPrimitives(), 163 | "Critical Native Methods may only use primitive JNI types as parameters"); 164 | 165 | return func(std::forward(args)...); 166 | } 167 | 168 | template 169 | template 170 | inline std::string CriticalMethod::desc() { 171 | return makeDescriptor(call); 172 | } 173 | 174 | } 175 | 176 | }} 177 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/Registration.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include "References.h" 21 | 22 | namespace facebook { 23 | namespace jni { 24 | 25 | namespace detail { 26 | 27 | // This uses the real JNI function as a non-type template parameter to 28 | // cause a (static member) function to exist with the same signature, 29 | // but with try/catch exception translation. 30 | template 31 | NativeMethodWrapper* exceptionWrapJNIMethod(R (*func0)(JNIEnv*, jobject, Args... args)); 32 | 33 | // Automatically wrap object argument, and don't take env explicitly. 34 | template 35 | NativeMethodWrapper* exceptionWrapJNIMethod(R (*func0)(alias_ref, Args... args)); 36 | 37 | // Extract C++ instance from object, and invoke given method on it, 38 | template 39 | NativeMethodWrapper* exceptionWrapJNIMethod(R (C::*method0)(Args... args)); 40 | 41 | // This uses deduction to figure out the descriptor name if the types 42 | // are primitive or have JObjectWrapper specializations. 43 | template 44 | std::string makeDescriptor(R (*func)(JNIEnv*, C, Args... args)); 45 | 46 | // This uses deduction to figure out the descriptor name if the types 47 | // are primitive or have JObjectWrapper specializations. 48 | template 49 | std::string makeDescriptor(R (*func)(alias_ref, Args... args)); 50 | 51 | // This uses deduction to figure out the descriptor name if the types 52 | // are primitive or have JObjectWrapper specializations. 53 | template 54 | std::string makeDescriptor(R (C::*method0)(Args... args)); 55 | 56 | template 57 | struct CriticalMethod; 58 | 59 | template 60 | struct CriticalMethod { 61 | template 62 | static R call(alias_ref, Args... args) noexcept; 63 | 64 | template 65 | inline static std::string desc(); 66 | }; 67 | 68 | } 69 | 70 | // We have to use macros here, because the func needs to be used 71 | // as both a decltype expression argument and as a non-type template 72 | // parameter, since C++ provides no way for translateException 73 | // to deduce the type of its non-type template parameter. 74 | // The empty string in the macros below ensures that name 75 | // is always a string literal (because that syntax is only 76 | // valid when name is a string literal). 77 | #define makeNativeMethod2(name, func) \ 78 | { name "", ::facebook::jni::detail::makeDescriptor(&func), \ 79 | ::facebook::jni::detail::exceptionWrapJNIMethod(&func) } 80 | 81 | #define makeNativeMethod3(name, desc, func) \ 82 | { name "", desc, \ 83 | ::facebook::jni::detail::exceptionWrapJNIMethod(&func) } 84 | 85 | // Variadic template hacks to get macros with different numbers of 86 | // arguments. Usage instructions are in CoreClasses.h. 87 | #define makeNativeMethodN(a, b, c, count, ...) makeNativeMethod ## count 88 | #define makeNativeMethod(...) makeNativeMethodN(__VA_ARGS__, 3, 2)(__VA_ARGS__) 89 | 90 | 91 | // FAST CALLS / CRITICAL CALLS 92 | // Android up to and including v7 supports "fast calls" by prefixing the method 93 | // signature with an exclamation mark. 94 | // Android v8+ supports fast calls by annotating methods: 95 | // https://source.android.com/devices/tech/dalvik/improvements#faster-native-methods 96 | 97 | // prefixes a JNI method signature as android "fast call". 98 | #if defined(__ANDROID__) && defined(FBJNI_WITH_FAST_CALLS) 99 | #define FBJNI_PREFIX_FAST_CALL(desc) (std::string{"!"} + desc) 100 | #else 101 | #define FBJNI_PREFIX_FAST_CALL(desc) (desc) 102 | #endif 103 | 104 | #define makeCriticalNativeMethod3(name, desc, func) \ 105 | makeNativeMethod3( \ 106 | name, \ 107 | FBJNI_PREFIX_FAST_CALL(desc), \ 108 | ::facebook::jni::detail::CriticalMethod::call<&func>) 109 | 110 | #define makeCriticalNativeMethod2(name, func) \ 111 | makeCriticalNativeMethod3( \ 112 | name, \ 113 | ::facebook::jni::detail::CriticalMethod::desc<&func>(), \ 114 | func) 115 | 116 | #define makeCriticalNativeMethodN(a, b, c, count, ...) makeCriticalNativeMethod ## count 117 | #define makeCriticalNativeMethod(...) makeCriticalNativeMethodN(__VA_ARGS__, 3, 2)(__VA_ARGS__) 118 | 119 | }} 120 | 121 | #include "Registration-inl.h" 122 | -------------------------------------------------------------------------------- /alloctrackSample/src/main/cpp/fb/fbjni/detail/TypeTraits.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018-present, Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | #include "References-forward.h" 22 | 23 | namespace facebook { 24 | namespace jni { 25 | 26 | /// Generic std::enable_if helper 27 | template 28 | using enable_if_t = typename std::enable_if::type; 29 | 30 | /// Generic std::is_convertible helper 31 | template 32 | constexpr bool IsConvertible() { 33 | return std::is_convertible::value; 34 | } 35 | 36 | template class TT, typename T> 37 | struct is_instantiation_of : std::false_type {}; 38 | 39 | template class TT, typename... Ts> 40 | struct is_instantiation_of> : std::true_type {}; 41 | 42 | template class TT, typename... Ts> 43 | constexpr bool IsInstantiationOf() { 44 | return is_instantiation_of::value; 45 | } 46 | 47 | /// Metafunction to determine whether a type is a JNI reference or not 48 | template 49 | struct is_plain_jni_reference : 50 | std::integral_constant::value && 52 | std::is_base_of< 53 | typename std::remove_pointer::type, 54 | typename std::remove_pointer::type>::value> {}; 55 | 56 | /// Helper to simplify use of is_plain_jni_reference 57 | template 58 | constexpr bool IsPlainJniReference() { 59 | return is_plain_jni_reference::value; 60 | } 61 | 62 | /// Metafunction to determine whether a type is a primitive JNI type or not 63 | template 64 | struct is_jni_primitive : 65 | std::integral_constant::value || 67 | std::is_same::value || 68 | std::is_same::value || 69 | std::is_same::value || 70 | std::is_same::value || 71 | std::is_same::value || 72 | std::is_same::value || 73 | std::is_same::value> {}; 74 | 75 | /// Helper to simplify use of is_jni_primitive 76 | template 77 | constexpr bool IsJniPrimitive() { 78 | return is_jni_primitive::value; 79 | } 80 | 81 | /// Metafunction to determine whether a series of types are all primitive JNI types. 82 | template 83 | struct are_jni_primitives; 84 | 85 | template 86 | struct are_jni_primitives : 87 | std::integral_constant::value && are_jni_primitives::value> {}; 89 | 90 | template<> 91 | struct are_jni_primitives<> : std::integral_constant {}; 92 | 93 | /// Helper to simplify use of are_jni_primitives 94 | template 95 | constexpr bool AreJniPrimitives() { 96 | return are_jni_primitives::value; 97 | } 98 | 99 | 100 | /// Metafunction to determine whether a type is a JNI array of primitives or not 101 | template 102 | struct is_jni_primitive_array : 103 | std::integral_constant::value || 105 | std::is_same::value || 106 | std::is_same::value || 107 | std::is_same::value || 108 | std::is_same::value || 109 | std::is_same::value || 110 | std::is_same::value || 111 | std::is_same::value> {}; 112 | 113 | /// Helper to simplify use of is_jni_primitive_array 114 | template 115 | constexpr bool IsJniPrimitiveArray() { 116 | return is_jni_primitive_array::value; 117 | } 118 | 119 | /// Metafunction to determine if a type is a scalar (primitive or reference) JNI type 120 | template 121 | struct is_jni_scalar : 122 | std::integral_constant::value || 124 | is_jni_primitive::value> {}; 125 | 126 | /// Helper to simplify use of is_jni_scalar 127 | template 128 | constexpr bool IsJniScalar() { 129 | return is_jni_scalar::value; 130 | } 131 | 132 | // Metafunction to determine if a type is a JNI type 133 | template 134 | struct is_jni_type : 135 | std::integral_constant::value || 137 | std::is_void::value> {}; 138 | 139 | /// Helper to simplify use of is_jni_type 140 | template 141 | constexpr bool IsJniType() { 142 | return is_jni_type::value; 143 | } 144 | 145 | template 146 | struct is_non_weak_reference : 147 | std::integral_constant() || 149 | IsInstantiationOf() || 150 | IsInstantiationOf()> {}; 151 | 152 | template 153 | constexpr bool IsNonWeakReference() { 154 | return is_non_weak_reference::value; 155 | } 156 | 157 | template 158 | struct is_any_reference : 159 | std::integral_constant() || 161 | IsInstantiationOf() || 162 | IsInstantiationOf() || 163 | IsInstantiationOf()> {}; 164 | 165 | template 166 | constexpr bool IsAnyReference() { 167 | return is_any_reference::value; 168 | } 169 | 170 | template 171 | struct reference_traits { 172 | using plain_jni_reference_t = JniType; 173 | static_assert(IsPlainJniReference(), "Need a plain JNI reference"); 174 | }; 175 | 176 | template