Skip to content

Commit e3861d8

Browse files
mrwillis21bklimtMarc Richardskmandrika
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 e3861d8

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)