Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modularise bugsnag-android into JVM, NDK, and ANR artefacts #522

Merged
merged 23 commits into from
Jul 18, 2019
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4439a57
rename sdk module to bugsnag-android-core
fractalwrench Jul 8, 2019
b6d8fa7
create initial gradle skeleton for modules
fractalwrench Jul 8, 2019
02e250e
move ndk to bugsnag-android-ndk module
fractalwrench Jul 8, 2019
4d4fe65
begin extracting anr into separate module
fractalwrench Jul 8, 2019
8829d81
setup plugin interface for ndk
fractalwrench Jul 10, 2019
219a1b8
create separate artefacts that compile in example project
fractalwrench Jul 11, 2019
d7420c1
create working ANR + NDK plugins
fractalwrench Jul 11, 2019
979d68d
add readmes to modules
fractalwrench Jul 11, 2019
6d7f330
begin passing lint
fractalwrench Jul 11, 2019
ea0973d
pass unit tests
fractalwrench Jul 11, 2019
f46f062
update contributing docs
fractalwrench Jul 11, 2019
95642a1
remove unused git submodule
fractalwrench Jul 11, 2019
4e05aa0
alter mazerunner tests to build against modularised artefacts
fractalwrench Jul 11, 2019
b268d21
rename plugins as requested
fractalwrench Jul 12, 2019
49ccfc5
rename bugsnag-plugin-android-jvm to bugsnag-android-core
fractalwrench Jul 15, 2019
0720ad3
use latest version of gradle plugin
fractalwrench Jul 15, 2019
3ed0615
review feedback
fractalwrench Jul 15, 2019
a247e2a
refactor: set DETECT_NDK_CRASHES in bugsnag-android-ndk artefact
fractalwrench Jul 15, 2019
3cdf062
attempt to fix buildkite ci
fractalwrench Jul 16, 2019
ee43c17
enable ndk/anr detection explicitly by default, as now using the bugs…
fractalwrench Jul 17, 2019
15e2801
update gradle plugin
fractalwrench Jul 17, 2019
d207fc1
Merge branch 'next' into artefact-modularisation
fractalwrench Jul 18, 2019
72ec766
browserstack mazerunner scenario tweaks
fractalwrench Jul 18, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "sdk/src/main/jni/external/libunwindstack"]
path = sdk/src/main/jni/external/libunwindstack
[submodule "bugsnag-android-ndk/src/main/jni/external/libunwindstack"]
path = bugsnag-android-ndk/src/main/jni/external/libunwindstack
url = https://github.com/bugsnag/libunwindstack-ndk
[submodule "bugsnag-android-ndk/src/main/jni/external/libunwindstack-ndk"]
path = bugsnag-android-ndk/src/main/jni/external/libunwindstack-ndk
url = https://github.com/bugsnag/libunwindstack-ndk
57 changes: 15 additions & 42 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,18 +84,18 @@ git submodule update --init --recursive
You can build new `.aar` files as follows:

```shell
./gradlew sdk:assemble
./gradlew assembleRelease
```

Files are generated into`sdk/build/outputs/aar`.
Files are generated into`<module>/build/outputs/aar`.

### Building with custom ABIs

To build the NDK module with specific ABIs, use the `ABI_FILTERS` project
option:

```shell
./gradlew assemble -PABI_FILTERS=x86,arm64-v8a
./gradlew assembleRelease -PABI_FILTERS=x86,arm64-v8a
```

## Testing
Expand All @@ -104,7 +104,7 @@ Full details of how to build and run tests can be found in [the testing guide](`

## Building the Example App

You can build and install the example app to as follows:
You can build and install the example app as follows:

```shell
./gradlew installDebug
Expand All @@ -115,41 +115,15 @@ device/emulator.

## Installing/testing against a local maven repository

Sometimes its helpful to build and install the bugsnag-android libraries into a
local repository and test the entire dependency flow inside of a sample
application.

To get started:

1. In the `bugsnag-android` directory, run
`./gradlew assembleRelease publishSDKPublicationToMavenLocal && ./gradlew assembleRelease publishSDKPublicationToMavenLocal -PreleaseNdkArtefact=true`.
This installs `bugsnag-android` and `bugsnag-android-ndk` into your local
maven repository.
2. In your sample application `build.gradle`, add `mavenLocal()` to the *top* of
your `allprojects` repositories section:

```groovy
allprojects {
repositories {
mavenLocal()
// other repos as needed
}
}
```
3. In your sample application `app/build.gradle`, add the following to the
dependencies section, inserting the exact version number required:

```groovy
dependencies {
implementation 'com.bugsnag:bugsnag-android-ndk:[VERSION NUMBER]'
}
```
4. Clean your sample application and reload dependencies *every time* you
rebuild/republish the local dependencies:

```
./gradlew clean --refresh-dependencies
```
Change `VERSION_NAME` in `gradle.properties` to a version higher than the currently
released bugsnag-android, then run:

```shell
./gradlew assembleRelease publishToMavenLocal
```

This installs bugsnag-android to a local maven repository. The example app should automatically use
this version when you next run the app.

# Releasing a New Version

Expand Down Expand Up @@ -224,12 +198,11 @@ If you are a project maintainer, you can build and release a new version of
- [ ] Update the version number and dex count badge by running `make VERSION=[number] bump`
- [ ] Inspect the updated CHANGELOG, README, and version files to ensure they are correct
- Once merged:
- Pull the latest changes (checking out master if necessary) and build by running `./gradlew sdk:assembleRelease`
- Pull the latest changes (checking out master if necessary) and build by running `./gradlew assembleRelease`
- Release to GitHub:
- [ ] Run `git tag vX.X.X && git push origin --tags`
- [ ] Create a release from your new tag on [GitHub Releases](https://github.com/bugsnag/bugsnag-android/releases)
- [ ] Upload the generated `.aar` file from `{sdk,ndk}/build/outputs/aar/bugsnag-android-*.aar`
fractalwrench marked this conversation as resolved.
Show resolved Hide resolved
- [ ] Release to Maven Central and Bintray by running `./gradlew sdk:assembleRelease publish bintrayUpload && ./gradlew sdk:assembleRelease publish bintrayUpload -PreleaseNdkArtefact=true`
- [ ] Release to Maven Central and Bintray by running `./gradlew assembleRelease publish bintrayUpload`
- [ ] "Promote" the release build on Maven Central:
- Go to the [sonatype open source dashboard](https://oss.sonatype.org/index.html#stagingRepositories)
- Click the search box at the top right, and type “com.bugsnag”
Expand Down
24 changes: 2 additions & 22 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
all: build

.PHONY: build test clean bump badge release
.PHONY: build test clean bump release

build:
./gradlew sdk:build
Expand Down Expand Up @@ -37,7 +37,7 @@ else
@APP_LOCATION=/app/build/fixture.apk docker-compose run android-maze-runner
endif

bump: badge
bump:
ifneq ($(shell git diff --staged),)
@git diff --staged
@$(error You have uncommitted changes. Push or discard them to continue)
Expand All @@ -51,26 +51,6 @@ endif
sdk/src/main/java/com/bugsnag/android/Notifier.java
@sed -i '' "s/## TBD/## $(VERSION) ($(shell date '+%Y-%m-%d'))/" CHANGELOG.md

badge: build
ifneq ($(shell git diff),)
@git diff
@$(error You have unstaged changes. Commit or discard them to continue)
endif
@echo "Counting ..."
@./gradlew countReleaseDexMethods > counter.txt
@awk 'BEGIN{ \
"cat counter.txt | grep \"com.bugsnag.android\$\"" | getline output;\
split(output, counts);\
"du -k sdk/build/outputs/aar/bugsnag-android-*.aar | cut -f1" | getline size;\
printf "![Method count and size](https://img.shields.io/badge/Methods%%20and%%20size-";\
printf counts[1] "%%20classes%%20|%%20" counts[2] "%%20methods%%20|%%20" counts[3] "%%20fields%%20|%%20";\
printf size "%%20KB-e91e63.svg)";\
};' > tmp_url.txt
@awk '/!.*Method count and size.*/ { getline < "tmp_url.txt" }1' README.md > README.md.tmp
@mv README.md.tmp README.md
@rm counter.txt tmp_url.txt


# Makes a release
release:
ifneq ($(shell git diff origin/master..master),)
Expand Down
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
# Bugsnag error monitoring & exception reporter for Android
[![Documentation](https://img.shields.io/badge/documentation-latest-blue.svg)](https://docs.bugsnag.com/platforms/android/)
[![Build status](https://api.travis-ci.com/bugsnag/bugsnag-android.svg?branch=master)](https://travis-ci.com/bugsnag/bugsnag-android)
[![Coverage Status](https://coveralls.io/repos/github/bugsnag/bugsnag-android/badge.svg?branch=master)](https://coveralls.io/github/bugsnag/bugsnag-android?branch=master)
<!-- Auto-generated line below: -->
![Method count and size](https://img.shields.io/badge/Methods%20and%20size-103%20classes%20|%20822%20methods%20|%20408%20fields%20|%202052%20KB-e91e63.svg)

Get comprehensive [Android crash reports](https://www.bugsnag.com/platforms/android/) to quickly debug errors.

Expand Down
29 changes: 15 additions & 14 deletions TESTING.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
# Testing the Bugsnag Android notifier

## Running Tests Locally
Commands can be run on the entire project, or on an individual module:

Running the test suite requires a connected android device or emulator.
```shell
./gradlew build // builds whole project
./gradlew bugsnag-android-anr:build // builds bugsnag-android-anr module only
```

## Static analysis

```shell
./gradlew lint checkstyle detekt
```

### Unit tests
## Running Tests Locally

You can run the test suite on a device/emulator as follows from within the sdk directory:
Running the test suite requires a connected android device or emulator.

```shell
./gradlew connectedCheck
```

### End-to-end tests
## End-to-end tests

To run the end-to-end tests, first set up the environment by running
[Bundler](https://bundler.io):
Expand All @@ -32,14 +41,6 @@ Then run the tests using:
bundle exec maze-runner
```

### Running Lint

You can run lint on the project using the following command:

```shell
./gradlew lint checkstyle detekt
```

## Running remote tests

These tests are implemented with our notifier testing tool [Maze runner](https://github.com/bugsnag/maze-runner).
Expand Down Expand Up @@ -95,4 +96,4 @@ Run `make remote-integration-tests`
If you wish to test a single feature, set the `TEST_FEATURE` environment variable to the name of the feature file.
For example, to test the `breadcrumb` feature, use the following command:

`TEST_FEATURE=breadcrumb.feature make remote-integration-tests`
`TEST_FEATURE=breadcrumb.feature make remote-integration-tests`
2 changes: 2 additions & 0 deletions bugsnag-android-anr/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cmake_minimum_required(VERSION 3.4.1)
add_subdirectory(src/main)
9 changes: 9 additions & 0 deletions bugsnag-android-anr/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# bugsnag-android
fractalwrench marked this conversation as resolved.
Show resolved Hide resolved

This module detects ANRs and reports them to bugsnag.

## High-level Overview

When an ANR dialog is shown SIGQUIT is raised. This module installs a SIGQUIT handler and sets a
ByteBuffer that is continuously monitored from the JVM. When the JVM code detects a ByteBuffer has
been modified, it generates a report of the ANR.
24 changes: 24 additions & 0 deletions bugsnag-android-anr/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apply plugin: "com.android.library"
apply plugin: "kotlin-android"
apply plugin: "io.gitlab.arturbosch.detekt"

android {
compileSdkVersion rootProject.ext.compileSdkVersion

defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
externalNativeBuild.cmake.arguments "-DANDROID_CPP_FEATURES=exceptions", "-DANDROID_STL=c++_static"
ndk.abiFilters = project.hasProperty("ABI_FILTERS") ? project.ABI_FILTERS.split(",") :
["arm64-v8a", "armeabi-v7a", "armeabi", "x86", "x86_64"]
}
externalNativeBuild.cmake.path = "CMakeLists.txt"
}

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

apply from: "../gradle/dependencies.gradle"
apply from: "../gradle/release.gradle"
apply from: "../gradle/detekt.gradle"
apply from: "../gradle/checkstyle.gradle"
2 changes: 2 additions & 0 deletions bugsnag-android-anr/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pomName=Bugsnag Android ANR
artefactId=bugsnag-android-anr
2 changes: 2 additions & 0 deletions bugsnag-android-anr/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-keepattributes LineNumberTable,SourceFile
-keep class com.bugsnag.android.AnrPlugin { *; }
2 changes: 2 additions & 0 deletions bugsnag-android-anr/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="com.bugsnag.android.anr" />
29 changes: 29 additions & 0 deletions bugsnag-android-anr/src/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
set(BUGSNAG_VERSION 1.0.1)
add_library( # Specifies the name of the library.
bugsnag-android-anr
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
jni/anr_handler.c
jni/bugsnag_anr.c
jni/utils/string.c
)

include_directories(jni)

find_library( # Defines the name of the path variable that stores the
# location of the NDK library.
log-lib
# Specifies the name of the NDK library that
# CMake needs to locate.
log )

target_link_libraries( # Specifies the target library.
bugsnag-android-anr
# Links the log library to the target library.
${log-lib})

set_target_properties(bugsnag-android-anr
PROPERTIES
COMPILE_OPTIONS
-Werror -Wall -pedantic)
27 changes: 27 additions & 0 deletions bugsnag-android-anr/src/main/java/com/bugsnag/android/AnrPlugin.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.bugsnag.android

import java.nio.ByteBuffer

internal class AnrPlugin : BugsnagPlugin {

private external fun installAnrDetection(sentinelBuffer: ByteBuffer)

override fun initialisePlugin(client: Client) {
System.loadLibrary("bugsnag-android-anr")
val delegate: (Thread) -> Unit = { handleAnr(it, client) }
val monitor = AppNotRespondingMonitor(delegate)
monitor.start()
installAnrDetection(monitor.sentinelBuffer)
Logger.info("Initialised ANR Plugin")
}

private fun handleAnr(thread: Thread, client: Client) {
val errMsg = "Application did not respond to UI input"
val exc = BugsnagException("ANR", errMsg, thread.stackTrace)

client.cacheAndNotify(
exc, Severity.ERROR, MetaData(),
HandledState.REASON_ANR, null, thread
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <android/log.h>

#include "../utils/crash_info.h"
#include "../utils/serializer.h"
#include "../utils/string.h"
#include "utils/string.h"

#ifndef BUGSNAG_LOG
#define BUGSNAG_LOG(fmt, ...) \
__android_log_print(ANDROID_LOG_WARN, "BugsnagNDK", fmt, ##__VA_ARGS__)
#endif

static pthread_t bsg_watchdog_thread;
static sigset_t bsg_anr_sigmask;
Expand Down
18 changes: 18 additions & 0 deletions bugsnag-android-anr/src/main/jni/bugsnag_anr.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include "bugsnag_anr.h"
#include "anr_handler.h"

#include <jni.h>

#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT void JNICALL Java_com_bugsnag_android_AnrPlugin_installAnrDetection(
JNIEnv *env, jobject _this, jobject byteBuffer) {
bsg_handler_install_anr((*env)->GetDirectBufferAddress(env, byteBuffer));
BUGSNAG_LOG("Initialization complete!");
}

#ifdef __cplusplus
}
#endif
21 changes: 21 additions & 0 deletions bugsnag-android-anr/src/main/jni/bugsnag_anr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* JNI interface between bugsnag-android-anr JVM and C++
*/
#ifndef BUGSNAG_ANR_H
#define BUGSNAG_ANR_H

#include <android/log.h>

#ifndef BUGSNAG_LOG
#define BUGSNAG_LOG(fmt, ...) \
__android_log_print(ANDROID_LOG_WARN, "BugsnagANR", fmt, ##__VA_ARGS__)
#endif

#ifdef __cplusplus
extern "C" {
#endif

#ifdef __cplusplus
}
#endif
#endif // BUGSNAG_NDK_H
13 changes: 13 additions & 0 deletions bugsnag-android-anr/src/main/jni/utils/string.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include <string.h>

void bsg_strncpy(char *dst, char *src, size_t len) {
int i = 0;
while (i <= len) {
char current = src[i];
dst[i] = current;
if (current == '\0') {
break;
}
i++;
}
}
Loading