Skip to content
This repository has been archived by the owner on Aug 30, 2023. It is now read-only.

Commit

Permalink
feat: NDK (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
bruno-garcia committed Oct 23, 2019
1 parent 0e1fe4d commit d815162
Show file tree
Hide file tree
Showing 16 changed files with 215 additions and 5 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ out/
local.properties
**.iml
*.hprof
.cxx
**/sentry-native-local
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "sentry-android-ndk/sentry-native"]
path = sentry-android-ndk/sentry-native
url = https://github.com/getsentry/sentry-native
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,14 @@ Android SDK for Sentry
[![AppVeyor](https://ci.appveyor.com/api/projects/status/kr49snupeb1dsgwa/branch/master?svg=true)](https://ci.appveyor.com/project/sentry/sentry-android/branch/master)
[![Tests](https://img.shields.io/appveyor/tests/sentry/sentry-android/master?compact_message)](https://ci.appveyor.com/project/sentry/sentry-android/branch/master/tests)
[![codecov](https://codecov.io/gh/getsentry/sentry-android/branch/master/graph/badge.svg)](https://codecov.io/gh/getsentry/sentry-android)

# Development

This repository includes [`sentry-native`](https://github.com/getsentry/sentry-native/) as a git submodule.
To build against `sentry-native` checked-out elsewhere in your file system, create a symlink `sentry-android-ndk/sentry-native-local` that points to your `sentry-native` directory.
For example, if you had `sentry-native` checked-out in a sibling directory to this repo:

`ln -s ../../sentry-native sentry-android-ndk/sentry-native-local`

which will be picked up by `gradle` and used instead of the git submodule.
This directory is also included in `.gitignore` not to be shown as pending changes.
1 change: 1 addition & 0 deletions buildSrc/src/main/java/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ object Config {

val buildToolsVersion = "29.0.2"
val minSdkVersion = 14
val minSdkVersionNdk = 21
val minSdkVersionDebug = 21
val targetSdkVersion = sdkVersion
val compileSdkVersion = sdkVersion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import android.content.Context;
import io.sentry.core.ILogger;
import io.sentry.core.SentryLevel;
import io.sentry.core.SentryOptions;
import java.io.File;
import java.lang.reflect.Method;

class AndroidOptionsInitializer {
static void init(SentryOptions options, Context context) {
Expand All @@ -19,6 +21,29 @@ static void init(SentryOptions options, Context context, ILogger logger) {

ManifestMetadataReader.applyMetadata(context, options);
createsEnvelopeDirPath(options, context);

if (options.isEnableNdk()) {
try {
// TODO: Create Integrations interface and use that to initialize NDK
Class<?> cls = Class.forName("io.sentry.android.ndk.SentryNdk");

// TODO: temporary hack
String cacheDirPath = context.getCacheDir().getAbsolutePath() + "/sentry-envelopes";
File f = new File(cacheDirPath);
f.mkdirs();

Method method = cls.getMethod("init", SentryOptions.class, String.class);
Object[] args = new Object[2];
args[0] = options;
args[1] = cacheDirPath;
method.invoke(null, args);
} catch (ClassNotFoundException exc) {
options.getLogger().log(SentryLevel.ERROR, "Failed to load SentryNdk.");
} catch (Exception e) {
options.getLogger().log(SentryLevel.ERROR, "Failed to initialize SentryNdk.", e);
}
}

options.addEventProcessor(new DefaultAndroidEventProcessor(context, options));
options.setSerializer(new AndroidSerializer(options.getLogger()));
}
Expand Down
16 changes: 16 additions & 0 deletions sentry-android-ndk/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
cmake_minimum_required(VERSION 3.4.1)
project("sentry-android")

# Adding sentry-native submodule subdirectory
add_subdirectory(${SENTRY_NATIVE_SRC})

# sentry-native submodule include path.
include_directories(${SENTRY_NATIVE_SRC}/include)

# sentry-native source code.
file(GLOB SENTRY_ANDROID_SOURCES ${CMAKE_SOURCE_DIR}/src/main/jni/*.c)

# Adding dynamic library and linking it with log and sentry-native.
add_library("sentry-android" SHARED ${SENTRY_ANDROID_SOURCES})
find_library(LOG_LIB log)
target_link_libraries("sentry-android" "sentry" ${LOG_LIB})
65 changes: 65 additions & 0 deletions sentry-android-ndk/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@

plugins {
id("com.android.library")
}

android {
compileSdkVersion(Config.Android.compileSdkVersion)
buildToolsVersion(Config.Android.buildToolsVersion)
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
defaultConfig {
targetSdkVersion(Config.Android.targetSdkVersion)
javaCompileOptions {
annotationProcessorOptions {
includeCompileClasspath = true
}
}

minSdkVersion(Config.Android.minSdkVersionNdk)
externalNativeBuild {
val sentryNativeSrc = if (File("${project.projectDir}/sentry-native-local").exists()) {
"sentry-native-local"
} else {
"sentry-native"
}
cmake {
arguments.add(0, "-DANDROID_STL=c++_static")
arguments.add(0, "-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON")
arguments.add(0, "-DSENTRY_NATIVE_SRC=" + sentryNativeSrc)
}
}
ndk {
val platform = System.getenv("ABI")
if (platform == null || platform.toLowerCase() == "all") {
abiFilters("x86", "armeabi-v7a", "x86_64", "arm64-v8a")
} else {
abiFilters(platform)
}
}

missingDimensionStrategy(Config.Flavors.dimension, Config.Flavors.production)
}

externalNativeBuild {
cmake {
setPath("CMakeLists.txt")
}
}
}

dependencies {
api(project(":sentry-core"))
api(project(":sentry-android-core"))
}

val initNative = tasks.register<Exec>("initNative") {
logger.log(LogLevel.LIFECYCLE, "Initializing git submodules")
commandLine("git", "submodule", "update", "--init", "--recursive")
}

tasks.named("preBuild") {
dependsOn(initNative)
}
1 change: 1 addition & 0 deletions sentry-android-ndk/sentry-native
Submodule sentry-native added at 03b86e
2 changes: 2 additions & 0 deletions sentry-android-ndk/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="io.sentry.android.ndk" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.sentry.android.ndk;

import io.sentry.core.SentryOptions;

public class SentryNdk {
static {
System.loadLibrary("sentry");
}

static {
System.loadLibrary("sentry-android");
}

private static native void initSentryNative(String cacheDirPath);

public static void notifyNewSerializedEnvelope(String path) {
System.out.println("envelope written to " + path);
}

public static void init(SentryOptions options, String cacheDirPath) {
// Java_example
initSentryNative(cacheDirPath);
}
}
52 changes: 52 additions & 0 deletions sentry-android-ndk/src/main/jni/sentry.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include <string.h>
#include <sentry.h>
#include <jni.h>
#include <malloc.h>
#include <android/log.h>

struct transport_options {
jmethodID notify_envelope_mid;
jclass cls;
JNIEnv *env;
char event_path[4096];
};

struct transport_options g_transport_options;

static void send_envelope(const sentry_envelope_t *envelope, void *data) {
char event_path[4096];
strcpy(event_path, g_transport_options.event_path);
strcat(event_path, "/test.envelope");
sentry_envelope_write_to_file(envelope, event_path);
jstring jevent_path = (*g_transport_options.env)->NewStringUTF(g_transport_options.env, event_path);
(*g_transport_options.env)->CallStaticVoidMethod(g_transport_options.env, g_transport_options.cls, g_transport_options.notify_envelope_mid, jevent_path);
}

JNIEXPORT void JNICALL Java_io_sentry_android_ndk_SentryNdk_initSentryNative(JNIEnv *env, jclass cls, jstring cache_dir_path) {
const char *path = (*env)->GetStringUTFChars(env, cache_dir_path, 0);
strcpy(g_transport_options.event_path, path);
g_transport_options.env = env;
g_transport_options.cls = cls;
g_transport_options.notify_envelope_mid = (*env)->GetStaticMethodID(env, cls, "notifyNewSerializedEnvelope", "(Ljava/lang/String;)V");

sentry_options_t *options = sentry_options_new();

sentry_options_set_transport(options, send_envelope, NULL);

sentry_options_set_environment(options, "Production");
sentry_options_set_release(options, "5fd7a6cd");
sentry_options_set_debug(options, 1);
sentry_options_set_dsn(options, "http://dfbecfd398754c73b6e8104538e89124@sentry.io/1322857");

sentry_init(options);

sentry_value_t event = sentry_value_new_event();
sentry_value_set_by_key(event, "message",
sentry_value_new_string("Hello World!"));

sentry_capture_event(event);

sentry_shutdown();

}

4 changes: 2 additions & 2 deletions sentry-android/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ android {

defaultConfig {
targetSdkVersion(Config.Android.targetSdkVersion)
minSdkVersion(Config.Android.minSdkVersion)
minSdkVersion(Config.Android.minSdkVersionNdk)
}

compileOptions {
Expand All @@ -26,5 +26,5 @@ android {

dependencies {
api(project(":sentry-android-core"))
// TODO: Add NDK: api(project(":sentry-android-ndk"))
api(project(":sentry-android-ndk"))
}
9 changes: 9 additions & 0 deletions sentry-core/src/main/java/io/sentry/core/SentryOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class SentryOptions {
private String dsn;
private long shutdownTimeoutMills;
private boolean debug;
private boolean enableNdk = true;
private @NonNull ILogger logger = NoOpLogger.getInstance();
private SentryLevel diagnosticLevel = DEFAULT_DIAGNOSTIC_LEVEL;
private ISerializer serializer;
Expand Down Expand Up @@ -79,6 +80,14 @@ public void setSerializer(ISerializer serializer) {
this.serializer = serializer;
}

public boolean isEnableNdk() {
return enableNdk;
}

public void setEnableNdk(boolean enableNdk) {
this.enableNdk = enableNdk;
}

public long getShutdownTimeout() {
return shutdownTimeoutMills;
}
Expand Down
2 changes: 1 addition & 1 deletion sentry-sample/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ android {

defaultConfig {
applicationId = "io.sentry.sample"
minSdkVersion(Config.Android.minSdkVersion)
minSdkVersion(Config.Android.minSdkVersionNdk) // NDK requires a higher API level than core.
targetSdkVersion(Config.Android.targetSdkVersion)
versionCode = 1
versionName = "1.0"
Expand Down
1 change: 0 additions & 1 deletion sentry-sample/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,4 @@
<meta-data android:name="io.sentry.debug" android:value="true" />
<!-- <meta-data android:name="io.sentry.auto-init" android:value="false" /> // how to disable the auto-init-->
</application>

</manifest>
2 changes: 1 addition & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
rootProject.name = "sentry"
rootProject.buildFileName = "build.gradle.kts"

include("sentry-android", "sentry-android-core", "sentry-core", "sentry-sample")
include("sentry-android", "sentry-android-ndk", "sentry-android-core", "sentry-core", "sentry-sample")

0 comments on commit d815162

Please sign in to comment.