Skip to content

Commit ddb14e8

Browse files
mrwillis21bklimtmrichardskmandrika
committed
Open Source Firebase Crashlytics for Android
Includes both Firebase Crashlytics and Firebase Crashlytics for NDK Initial release candidate for version 17.0.0-beta01 Co-authored-by: Bryan Klimt <[email protected]> Co-authored-by: Marc Richards <[email protected]> Co-authored-by: Konstantin Mandrika <[email protected]>
1 parent e114571 commit ddb14e8

File tree

229 files changed

+52914
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

229 files changed

+52914
-0
lines changed

.gitmodules

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[submodule "firebase-crashlytics-ndk/src/third_party/breakpad"]
2+
path = firebase-crashlytics-ndk/src/third_party/breakpad
3+
url = https://chromium.googlesource.com/breakpad/breakpad
4+
[submodule "firebase-crashlytics-ndk/src/third_party/lss"]
5+
path = firebase-crashlytics-ndk/src/third_party/lss
6+
url = https://chromium.googlesource.com/linux-syscall-support

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ dependencies:
77
* `firebase-abt`
88
* `firebase-common`
99
* `firebase-common-ktx`
10+
* `firebase-crashlytics`
11+
* `firebase-crashlytics-ndk`
1012
* `firebase-database`
1113
* `firebase-database-ktx`
1214
* `firebase-database-collection`

firebase-crashlytics-ndk/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Firebase Crashlytics NDK Component
2+
3+
This component enables NDK crash reporting with Crashlytics.
4+
5+
Requires NDK version r17c to build.
6+
7+
## Building
8+
9+
All Gradle commands should be run from the root of this repository.
10+
11+
`./gradlew :firebase-crashlytics-ndk:assemble`
12+
13+
## Running Tests
14+
15+
Integration tests, requiring a running and connected device (emulator or real):
16+
`./gradlew :firebase-crashlytics-ndk:connectedAndroidTest`
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright 2018 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
plugins {
16+
id 'firebase-library'
17+
}
18+
19+
firebaseLibrary {
20+
testLab.enabled = true
21+
publishJavadoc = false
22+
}
23+
24+
def androidVersion = 28
25+
26+
android {
27+
adbOptions {
28+
timeOutInMs 60 * 1000
29+
}
30+
31+
compileSdkVersion androidVersion
32+
defaultConfig {
33+
minSdkVersion 16
34+
targetSdkVersion androidVersion
35+
versionName version
36+
37+
multiDexEnabled true
38+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
39+
}
40+
sourceSets {
41+
androidTest {
42+
java {
43+
}
44+
}
45+
}
46+
compileOptions {
47+
sourceCompatibility JavaVersion.VERSION_1_8
48+
targetCompatibility JavaVersion.VERSION_1_8
49+
}
50+
51+
externalNativeBuild {
52+
ndkBuild {
53+
path "./src/main/jni/Android.mk"
54+
}
55+
}
56+
}
57+
58+
dependencies {
59+
implementation project(':firebase-common')
60+
implementation project(':firebase-crashlytics')
61+
implementation 'com.google.android.gms:play-services-basement:17.0.0'
62+
63+
testImplementation 'androidx.test:runner:1.2.0'
64+
testImplementation 'org.robolectric:robolectric:4.2'
65+
testImplementation 'junit:junit:4.12'
66+
testImplementation 'org.mockito:mockito-core:1.10.19'
67+
68+
androidTestImplementation 'androidx.test:runner:1.2.0'
69+
androidTestImplementation 'androidx.test:core:1.2.0'
70+
androidTestImplementation 'org.mockito:mockito-core:2.25.0'
71+
androidTestImplementation 'com.linkedin.dexmaker:dexmaker:2.25.0'
72+
androidTestImplementation 'com.linkedin.dexmaker:dexmaker-mockito:2.25.0'
73+
androidTestImplementation 'com.google.protobuf:protobuf-java:3.6.1'
74+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
version=17.0.0-beta01
2+
latestReleasedVersion=17.0.0-beta01
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright 2019 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.crashlytics.ndk;
16+
17+
import static org.mockito.Mockito.mock;
18+
import static org.mockito.Mockito.when;
19+
20+
import android.content.Context;
21+
import androidx.test.core.app.ApplicationProvider;
22+
import java.io.File;
23+
import java.io.IOException;
24+
import java.util.UUID;
25+
import junit.framework.TestCase;
26+
27+
public class BreakpadControllerTest extends TestCase {
28+
29+
private BreakpadController controller;
30+
31+
private Context context;
32+
private NativeApi mockNativeApi;
33+
private CrashFilesManager mockFilesManager;
34+
35+
private File testFilesDirectory;
36+
37+
@Override
38+
protected void setUp() throws Exception {
39+
super.setUp();
40+
context = ApplicationProvider.getApplicationContext();
41+
mockNativeApi = mock(NativeApi.class);
42+
mockFilesManager = mock(CrashFilesManager.class);
43+
controller = new BreakpadController(context, mockNativeApi, mockFilesManager);
44+
}
45+
46+
@Override
47+
protected void tearDown() throws Exception {
48+
recursiveDelete(testFilesDirectory);
49+
super.tearDown();
50+
}
51+
52+
private static void recursiveDelete(File file) {
53+
if (file == null) {
54+
return;
55+
}
56+
if (file.isDirectory()) {
57+
for (File f : file.listFiles()) {
58+
recursiveDelete(f);
59+
}
60+
}
61+
file.delete();
62+
}
63+
64+
private boolean setupTestFilesDirectory() {
65+
// For each test case, create a new, random subdirectory to guarantee a clean slate for file
66+
// manipulation.
67+
testFilesDirectory = new File(context.getFilesDir(), UUID.randomUUID().toString());
68+
return testFilesDirectory.mkdirs();
69+
}
70+
71+
public void testHasCrashDataForSession() throws IOException {
72+
assertTrue(setupTestFilesDirectory());
73+
assertTrue(new File(testFilesDirectory, "crash.dmp").createNewFile());
74+
final String sessionId = "test";
75+
when(mockFilesManager.hasSessionFileDirectory(sessionId)).thenReturn(true);
76+
when(mockFilesManager.getSessionFileDirectory(sessionId)).thenReturn(testFilesDirectory);
77+
assertTrue(controller.hasCrashDataForSession("test"));
78+
}
79+
80+
public void testHasCrashDataForSession_noCrashDataReturnsFalse() {
81+
final String sessionId = "test";
82+
when(mockFilesManager.hasSessionFileDirectory(sessionId)).thenReturn(false);
83+
assertFalse(controller.hasCrashDataForSession("test"));
84+
}
85+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2019 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.crashlytics.ndk;
16+
17+
import static org.mockito.Mockito.mock;
18+
import static org.mockito.Mockito.when;
19+
20+
import junit.framework.TestCase;
21+
22+
public class FirebaseCrashlyticsNdkTest extends TestCase {
23+
24+
private FirebaseCrashlyticsNdk nativeComponent;
25+
26+
private NativeComponentController mockController;
27+
28+
@Override
29+
protected void setUp() throws Exception {
30+
super.setUp();
31+
mockController = mock(NativeComponentController.class);
32+
nativeComponent = new FirebaseCrashlyticsNdk(mockController);
33+
}
34+
35+
@Override
36+
protected void tearDown() throws Exception {
37+
super.tearDown();
38+
}
39+
40+
public void testHasCrashDataForSession() {
41+
final String sessionId = "test";
42+
when(mockController.hasCrashDataForSession(sessionId)).thenReturn(true);
43+
assertTrue(nativeComponent.hasCrashDataForSession("test"));
44+
}
45+
46+
public void testHasCrashDataForSession_noCrashDataReturnsFalse() {
47+
final String sessionId = "test";
48+
when(mockController.hasCrashDataForSession(sessionId)).thenReturn(false);
49+
assertFalse(nativeComponent.hasCrashDataForSession("test"));
50+
}
51+
52+
public void testHasCrashDataForSession_nullSessionIdReturnsFalse() {
53+
assertFalse(nativeComponent.hasCrashDataForSession(null));
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Copyright 2019 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.crashlytics.ndk.utils;
16+
17+
public class TestMapEntry {
18+
public static final String FORMAT_ENTRY = "%08x-%08x %s %08x %s %d %s";
19+
20+
private static final long DEFAULT_START_ADDRESS = 0L;
21+
private static final long DEFAULT_END_ADDRESS = 64L;
22+
private static final String DEFAULT_PERMS = "rwxp";
23+
private static final long DEFAULT_OFFSET = 0L;
24+
private static final String DEFAULT_DEVICE = "03:0c";
25+
private static final int DEFAULT_INODE = 7;
26+
private static final String DEFAULT_PATH = "/valid/path";
27+
28+
private String outputFormat = FORMAT_ENTRY;
29+
30+
public long startAddress;
31+
public long endAddress;
32+
public String permissions;
33+
public long offset;
34+
public String device;
35+
public int inode;
36+
public String path;
37+
38+
public TestMapEntry() {
39+
this(
40+
DEFAULT_START_ADDRESS,
41+
DEFAULT_END_ADDRESS,
42+
DEFAULT_PERMS,
43+
DEFAULT_OFFSET,
44+
DEFAULT_DEVICE,
45+
DEFAULT_INODE,
46+
DEFAULT_PATH);
47+
}
48+
49+
public TestMapEntry(long startAddress, long size, String path) {
50+
this(startAddress, startAddress + size, DEFAULT_PERMS, path);
51+
}
52+
53+
public TestMapEntry(long startAddress, long size, String perms, String path) {
54+
this(
55+
startAddress,
56+
startAddress + size,
57+
perms,
58+
DEFAULT_OFFSET,
59+
DEFAULT_DEVICE,
60+
DEFAULT_INODE,
61+
path);
62+
}
63+
64+
public TestMapEntry(
65+
long startAddress,
66+
long endAddress,
67+
String permissions,
68+
long offset,
69+
String device,
70+
int inode,
71+
String path) {
72+
this.startAddress = startAddress;
73+
this.endAddress = endAddress;
74+
this.permissions = permissions;
75+
this.offset = offset;
76+
this.device = device;
77+
this.inode = inode;
78+
this.path = path;
79+
}
80+
81+
public void setToStringFormat(String format) {
82+
this.outputFormat = format;
83+
}
84+
85+
@Override
86+
public String toString() {
87+
return String.format(
88+
outputFormat, startAddress, endAddress, permissions, offset, device, inode, path);
89+
}
90+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{"pc":2934348926,"symbol":"_ZN4boom7explodeEi"}
2+
{"si_addr":0,"sig_name":"SIGSEGV","sig_code":"SEGV_MAPERR"}
3+
{"time":1473795194}
4+
{"version":"1.1.3"}
5+
{"orientation":1,"total_physical_memory":
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{"pc":2934348926,"symbol":"_ZN4boom7explodeEi"}
2+
{"si_addr":0,"sig_name":"SIGSEGV","sig_code":"SEGV_MAPERR"}
3+
{"time":1473795194}
4+
{"version":"1.1.3"}
5+
{"orientation":1,"total_physical_memory":1945096192,"total_internal_storage":28734615552,"available_physical_memory":64888832,"available_internal_storage":15769907200,"battery":94,"proximity_enabled":true}
6+
{"unwind_impl":"libunwind"}
7+
{"maps":["ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]","be45c000-bec5b000 rw-p 00000000 00:00 0 [stack]","be45c000-be45c000 ---p 00000000 00:00 0 ","b6f3f000-b6f40000 rw-p 00000000 00:00 0 ","b6f3e000-b6f3f000 r--p 4000 00:00 0 /system/bin/app_process32","b6f39000-b6f3e000 r-xp 00000000 00:00 0 /system/bin/app_process32","ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]","be45c000-bec5b000 rw-p 00000000 00:00 0 [stack]","be45c000-be45c000 ---p 00000000 00:00 0 ","b6f3f000-b6f40000 rw-p 00000000 00:00 0 ","b6f3e000-b6f3f000 r--p 4000 00:00 0 /system/bin/app_process32","b6f39000-b6f3e000 r-xp 00000000 00:00 0 /system/bin/app_process32","b6f37000-b6f39000 rw-p 00000000 00:00 0 ","b6f35000-b6f37000 rw-p 1d000 00:00 0 /system/bin/linker","b6f34000-b6f35000 r--p 1c000 00:00 0 /system/bin/linker","b6f17000-b6f34000 r-xp 00000000 00:00 0 /system/bin/linker","b6f15000-b6f17000 rw-p 00000000 00:00 0 [anon:thread signal stack]","b6f14000-b6f15000 ---p 00000000 00:00 0 ","b6f13000-b6f14000 r--p 00000000 00:00 0 ","b6ef3000-b6f13000 r--p 00000000 00:00 0 /dev/__properties__","b6ef2000-b6ef3000 r--p 00000000 00:00 0 [anon:linker_alloc]","b6ef1000-b6ef2000 rw-p 00000000 00:00 0 [anon:linker_alloc_32]","b6ef0000-b6ef1000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]","b6eef000-b6ef0000 rw-p 00000000 00:00 0 [anon:linker_alloc]","b6eed000-b6eef000 r--p 00000000 00:00 0 [anon:linker_alloc]","b6eec000-b6eed000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]","b6eeb000-b6eec000 rw-p f000 00:00 0 /system/lib/libcutils.so","b6eea000-b6eeb000 r--p e000 00:00 0 /system/lib/libcutils.so","b6ee9000-b6eea000 ---p 00000000 00:00 0 ","b6edb000-b6ee9000 r-xp 00000000 00:00 0 /system/lib/libcutils.so","b6eda000-b6edb000 rw-p 19000 00:00 0 /system/lib/libutils.so","b6ed9000-b6eda000 r--p 18000 00:00 0 /system/lib/libutils.so","b6ed8000-b6ed9000 ---p 00000000 00:00 0 ","b6ec0000-b6ed8000 r-xp 00000000 00:00 0 /system/lib/libutils.so","b6ebf000-b6ec0000 rw-p 00000000 00:00 0 [anon:linker_alloc]","b6ebe000-b6ebf000 rw-p 8000 00:00 0 /system/lib/liblog.so","b6ebd000-b6ebe000 r--p 7000 00:00 0 /system/lib/liblog.so","b6eb5000-b6ebd000 r-xp 00000000 00:00 0 /system/lib/liblog.so","b6eb4000-b6eb5000 rw-p 2c000 00:00 0 /system/lib/libbinder.so","b6ead000-b6eb4000 r--p 25000 00:00 0 /system/lib/libbinder.so","b6eac000-b6ead000 ---p 00000000 00:00 0 ","b6e87000-b6eac000 r-xp 00000000 00:00 0 /system/lib/libbinder.so","b6e83000-b6e87000 r--p 00000000 00:00 0 [anon:linker_alloc]","b6e82000-b6e83000 rw-p 00000000 00:00 0 [anon:linker_alloc_64]","b6e81000-b6e82000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]","b6e79000-b6e81000 rw-p d3000 00:00 0 /system/lib/libandroid_runtime.so","b6e73000-b6e79000 r--p cd000 00:00 0 /system/lib/libandroid_runtime.so","b6e72000-b6e73000 ---p 00000000 00:00 0 ","b6da5000-b6e72000 r-xp 00000000 00:00 0 /system/lib/libandroid_runtime.so","b6da4000-b6da5000 rw-p 2b000 00:00 0 /system/lib/libwilhelm.so","b6da1000-b6da4000 r--p 28000 00:00 0 /system/lib/libwilhelm.so","b6da0000-b6da1000 ---p 00000000 00:00 0 ","b6d78000-b6da0000 r-xp 00000000 00:00 0 /system/lib/libwilhelm.so","b6d77000-b6d78000 rw-p 00000000 00:00 0 ","b6d76000-b6d77000 rw-p 8c000 00:00 0 /system/lib/libc++.so”]}
8+
{"threads":[{
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
~ ATTRIBUTIONS:
4+
5+
~ libunwind - a platform-independent unwind library
6+
~ Copyright (C) 2012 Tommi Rantala <[email protected]>
7+
~ Copyright (C) 2013 Linaro Limited
8+
~ Copyright (C) 2008 CodeSourcery
9+
~
10+
~ you may not use these libunwind except in compliance with the License.
11+
~ You may obtain a copy of the License at
12+
~
13+
~ http://www.apache.org/licenses/LICENSE-2.0
14+
~
15+
~ Unless required by applicable law or agreed to in writing, software
16+
~ distributed under the License is distributed on an "AS IS" BASIS,
17+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
~ See the License for the specific language governing permissions and
19+
~ limitations under the License.
20+
~
21+
~
22+
-->
23+
<manifest package="com.crashlytics.android.ndk"
24+
xmlns:android="http://schemas.android.com/apk/res/android">
25+
26+
<application>
27+
<service android:name="com.google.firebase.components.ComponentDiscoveryService" android:exported="false">
28+
<meta-data android:name="com.google.firebase.components:com.google.firebase.crashlytics.ndk.CrashlyticsNdkRegistrar"
29+
android:value="com.google.firebase.components.ComponentRegistrar" />
30+
</service>
31+
</application>
32+
</manifest>

0 commit comments

Comments
 (0)