Skip to content

Commit af810db

Browse files
mrwillis21jakeouellette
authored andcommitted
Implement strategy pattern for native sessions
1 parent 2f3dab0 commit af810db

6 files changed

+151
-113
lines changed

firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/CrashlyticsController.java

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,9 @@
3232
import com.google.firebase.analytics.connector.AnalyticsConnector;
3333
import com.google.firebase.crashlytics.internal.CrashlyticsNativeComponent;
3434
import com.google.firebase.crashlytics.internal.Logger;
35-
import com.google.firebase.crashlytics.internal.NativeSessionFileProvider;
3635
import com.google.firebase.crashlytics.internal.analytics.AnalyticsConnectorReceiver;
3736
import com.google.firebase.crashlytics.internal.analytics.AnalyticsReceiver;
3837
import com.google.firebase.crashlytics.internal.log.LogFileManager;
39-
import com.google.firebase.crashlytics.internal.ndk.NativeFileUtils;
4038
import com.google.firebase.crashlytics.internal.network.HttpRequestFactory;
4139
import com.google.firebase.crashlytics.internal.persistence.FileStore;
4240
import com.google.firebase.crashlytics.internal.proto.ClsFileOutputStream;
@@ -58,8 +56,10 @@
5856
import com.google.firebase.crashlytics.internal.stacktrace.StackTraceTrimmingStrategy;
5957
import com.google.firebase.crashlytics.internal.stacktrace.TrimmedThrowableData;
6058
import com.google.firebase.crashlytics.internal.unity.UnityVersionProvider;
59+
import java.io.ByteArrayInputStream;
6160
import java.io.File;
6261
import java.io.FileInputStream;
62+
import java.io.FileNotFoundException;
6363
import java.io.FileOutputStream;
6464
import java.io.FilenameFilter;
6565
import java.io.IOException;
@@ -85,7 +85,6 @@
8585
import java.util.concurrent.atomic.AtomicInteger;
8686
import java.util.regex.Matcher;
8787
import java.util.regex.Pattern;
88-
import java.util.zip.GZIPOutputStream;
8988

9089
@SuppressWarnings("PMD")
9190
class CrashlyticsController {
@@ -1104,12 +1103,48 @@ public boolean accept(File dir, String filename) {
11041103
// endregion
11051104

11061105
private void finalizePreviousNativeSession(String previousSessionId) throws IOException {
1107-
// TODO: Provide a set of inputstreams?
1108-
// reportingCoordinator.persistNativeEvent(nativeSessionDirectory);
1106+
Logger.getLogger().d("Finalizing native report for session " + previousSessionId);
1107+
final GzipFileNativeSessionProcessingStrategy strategy =
1108+
new GzipFileNativeSessionProcessingStrategy(
1109+
context, (sessionId) -> new File(getNativeSessionFilesDir(), sessionId));
1110+
1111+
final File filesDir = getFilesDir();
1112+
final MetaDataStore metaDataStore = new MetaDataStore(filesDir);
1113+
final File userFile = metaDataStore.getUserDataFileForSession(previousSessionId);
1114+
final File keysFile = metaDataStore.getKeysFileForSession(previousSessionId);
1115+
1116+
final LogFileManager previousSessionLogManager =
1117+
new LogFileManager(getContext(), logFileDirectoryProvider, previousSessionId);
1118+
byte[] logBytes = previousSessionLogManager.getBytesForLog();
1119+
1120+
InputStream keysInput = null;
1121+
InputStream logsInput = null;
1122+
InputStream userInput = null;
1123+
try {
1124+
userInput = openFileStream(userFile);
1125+
keysInput = openFileStream(keysFile);
1126+
if (logBytes != null && logBytes.length > 0) {
1127+
logsInput = new ByteArrayInputStream(logBytes);
1128+
}
1129+
strategy.processNativeSession(
1130+
nativeComponent, previousSessionId, keysInput, logsInput, userInput);
1131+
} finally {
1132+
CommonUtils.closeQuietly(keysInput);
1133+
CommonUtils.closeQuietly(logsInput);
1134+
CommonUtils.closeQuietly(userInput);
1135+
}
11091136

1137+
previousSessionLogManager.clearLog();
1138+
}
11101139

1111-
// TODO: Do this in the gzipfilenativething
1112-
// previousSessionLogManager.clearLog();
1140+
private static FileInputStream openFileStream(File f) {
1141+
FileInputStream stream;
1142+
try {
1143+
stream = new FileInputStream(f);
1144+
} catch (FileNotFoundException fnf) {
1145+
stream = null;
1146+
}
1147+
return stream;
11131148
}
11141149

11151150
/** Removes dashes in the Crashlytics session identifier to conform to Firebase constraints. */

firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/CrashlyticsNativeReportGenerator.java

Lines changed: 0 additions & 59 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2020 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.internal.common;
16+
17+
import com.google.firebase.crashlytics.internal.CrashlyticsNativeComponent;
18+
import com.google.firebase.crashlytics.internal.model.CrashlyticsReport;
19+
import java.io.IOException;
20+
import java.io.InputStream;
21+
22+
class CrashlyticsReportNativeSessionProcessingStrategy
23+
implements NativeSessionProcessingStrategy<CrashlyticsReport> {
24+
25+
@Override
26+
public CrashlyticsReport processNativeSession(
27+
CrashlyticsNativeComponent nativeComponent,
28+
String sessionId,
29+
InputStream keysInput,
30+
InputStream logsInput,
31+
InputStream userInput)
32+
throws IOException {
33+
return null;
34+
}
35+
}
Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,44 @@
1414

1515
package com.google.firebase.crashlytics.internal.common;
1616

17+
import android.content.Context;
1718
import androidx.annotation.NonNull;
1819
import androidx.annotation.Nullable;
19-
import com.google.firebase.crashlytics.core.MetaDataStore;
2020
import com.google.firebase.crashlytics.internal.CrashlyticsNativeComponent;
2121
import com.google.firebase.crashlytics.internal.Logger;
2222
import com.google.firebase.crashlytics.internal.NativeSessionFileProvider;
23-
import com.google.firebase.crashlytics.internal.log.LogFileManager;
2423
import com.google.firebase.crashlytics.internal.ndk.NativeFileUtils;
25-
import com.google.firebase.crashlytics.internal.persistence.FileStore;
24+
import java.io.ByteArrayInputStream;
2625
import java.io.File;
2726
import java.io.FileInputStream;
2827
import java.io.FileOutputStream;
2928
import java.io.IOException;
29+
import java.io.InputStream;
3030
import java.util.zip.GZIPOutputStream;
3131

32-
class GzipFileNativeSessionHandler implements NativeComponentSessionHandler<Void> {
32+
class GzipFileNativeSessionProcessingStrategy implements NativeSessionProcessingStrategy<Void> {
3333

34-
private CrashlyticsNativeComponent nativeComponent;
35-
private FileStore fileStore;
34+
interface OutputDirectoryProvider {
35+
File getOutputDirectory(String sessionId);
36+
}
37+
38+
private final Context context;
39+
private final OutputDirectoryProvider outputDirectoryProvider;
40+
41+
public GzipFileNativeSessionProcessingStrategy(
42+
Context context, OutputDirectoryProvider outputDirectoryProvider) {
43+
this.context = context;
44+
this.outputDirectoryProvider = outputDirectoryProvider;
45+
}
3646

3747
@Override
38-
public Void handlePreviousNativeSession(String sessionId) throws IOException {
48+
public Void processNativeSession(
49+
CrashlyticsNativeComponent nativeComponent,
50+
String sessionId,
51+
InputStream keysInput,
52+
InputStream logsInput,
53+
InputStream userInput)
54+
throws IOException {
3955
Logger.getLogger().d("Finalizing native report for session " + sessionId);
4056
NativeSessionFileProvider nativeSessionFileProvider =
4157
nativeComponent.getSessionFileProvider(sessionId);
@@ -53,74 +69,71 @@ public Void handlePreviousNativeSession(String sessionId) throws IOException {
5369
return null;
5470
}
5571

56-
final File filesDir = fileStore.getFilesDir();
57-
final MetaDataStore metaDataStore = new MetaDataStore(filesDir);
58-
final File sessionUser = metaDataStore.getUserDataFileForSession(sessionId);
59-
final File sessionKeys = metaDataStore.getKeysFileForSession(sessionId);
60-
61-
final LogFileManager previousSessionLogManager =
62-
new LogFileManager(getContext(), logFileDirectoryProvider, sessionId);
63-
final byte[] logs = previousSessionLogManager.getBytesForLog();
64-
65-
final File nativeSessionDirectory = new File(getNativeSessionFilesDir(), sessionId);
72+
final File nativeSessionDirectory = outputDirectoryProvider.getOutputDirectory(sessionId);
6673

6774
if (!nativeSessionDirectory.mkdirs()) {
6875
Logger.getLogger().d("Couldn't create native sessions directory");
69-
return;
76+
return null;
7077
}
7178

7279
gzipFile(minidump, new File(nativeSessionDirectory, "minidump"));
73-
gzipIfNotEmpty(
80+
gzipBytes(
7481
NativeFileUtils.binaryImagesJsonFromMapsFile(binaryImages, context),
7582
new File(nativeSessionDirectory, "binaryImages"));
7683
gzipFile(metadata, new File(nativeSessionDirectory, "metadata"));
7784
gzipFile(sessionFile, new File(nativeSessionDirectory, "session"));
7885
gzipFile(sessionApp, new File(nativeSessionDirectory, "app"));
7986
gzipFile(sessionDevice, new File(nativeSessionDirectory, "device"));
8087
gzipFile(sessionOs, new File(nativeSessionDirectory, "os"));
81-
gzipFile(sessionUser, new File(nativeSessionDirectory, "user"));
82-
gzipFile(sessionKeys, new File(nativeSessionDirectory, "keys"));
83-
gzipIfNotEmpty(logs, new File(nativeSessionDirectory, "logs"));
88+
gzipInputStream(userInput, new File(nativeSessionDirectory, "user"));
89+
gzipInputStream(keysInput, new File(nativeSessionDirectory, "keys"));
90+
gzipInputStream(logsInput, new File(nativeSessionDirectory, "logs"));
8491

8592
return null;
8693
}
8794

88-
private static void gzipFile(@NonNull File input, @NonNull File output) throws IOException {
89-
if (!input.exists() || !input.isFile()) {
95+
private static void gzipBytes(@Nullable byte[] bytes, @NonNull File outputFile)
96+
throws IOException {
97+
if (bytes == null || bytes.length == 0) {
98+
return;
99+
}
100+
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
101+
try {
102+
gzipInputStream(bis, outputFile);
103+
} finally {
104+
CommonUtils.closeQuietly(bis);
105+
}
106+
}
107+
108+
private static void gzipFile(@Nullable File input, @NonNull File outputFile) throws IOException {
109+
if (input == null) {
90110
return;
91111
}
92-
byte[] buffer = new byte[1024];
93112
FileInputStream fis = null;
94-
GZIPOutputStream gos = null;
95113
try {
96114
fis = new FileInputStream(input);
97-
gos = new GZIPOutputStream(new FileOutputStream(output));
98-
99-
int read;
100-
101-
while ((read = fis.read(buffer)) > 0) {
102-
gos.write(buffer, 0, read);
103-
}
104-
105-
gos.finish();
115+
gzipInputStream(fis, outputFile);
106116
} finally {
107117
CommonUtils.closeQuietly(fis);
108-
CommonUtils.closeQuietly(gos);
109118
}
110119
}
111120

112-
private static void gzipIfNotEmpty(@Nullable byte[] content, @NonNull File path)
121+
private static void gzipInputStream(@Nullable InputStream input, @NonNull File output)
113122
throws IOException {
114-
if (content != null && content.length > 0) {
115-
gzip(content, path);
123+
if (input == null) {
124+
return;
116125
}
117-
}
118-
119-
private static void gzip(@NonNull byte[] bytes, @NonNull File path) throws IOException {
126+
byte[] buffer = new byte[1024];
120127
GZIPOutputStream gos = null;
121128
try {
122-
gos = new GZIPOutputStream(new FileOutputStream(path));
123-
gos.write(bytes, 0, bytes.length);
129+
gos = new GZIPOutputStream(new FileOutputStream(output));
130+
131+
int read;
132+
133+
while ((read = input.read(buffer)) > 0) {
134+
gos.write(buffer, 0, read);
135+
}
136+
124137
gos.finish();
125138
} finally {
126139
CommonUtils.closeQuietly(gos);
Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,21 @@
1414

1515
package com.google.firebase.crashlytics.internal.common;
1616

17+
import com.google.firebase.crashlytics.internal.CrashlyticsNativeComponent;
1718
import java.io.IOException;
19+
import java.io.InputStream;
1820

19-
interface NativeComponentSessionHandler<T> {
20-
T handlePreviousNativeSession(String sessionId) throws IOException;
21+
/**
22+
* Strategy for processing session data from the {@link CrashlyticsNativeComponent}
23+
*
24+
* @param <T> processed session output type
25+
*/
26+
interface NativeSessionProcessingStrategy<T> {
27+
T processNativeSession(
28+
CrashlyticsNativeComponent nativeComponent,
29+
String sessionId,
30+
InputStream keysInput,
31+
InputStream logsInput,
32+
InputStream userInput)
33+
throws IOException;
2134
}

firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/SessionReportingCoordinator.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ public void persistNativeEvent(@NonNull File nativeEventFilesDir) {
146146
gzipFile(sessionUser, new File(nativeSessionDirectory, "user"));
147147
gzipFile(sessionKeys, new File(nativeSessionDirectory, "keys"));
148148
gzipIfNotEmpty(logs, new File(nativeSessionDirectory, "logs"));*/
149-
final FilesPayload.File minidump = FilesPayload.File.builder().setFilename("minidump_file").setContents(new byte[0]).build();
149+
final FilesPayload.File minidump =
150+
FilesPayload.File.builder().setFilename("minidump_file").setContents(new byte[0]).build();
150151
}
151152

152153
public void persistUserId() {

0 commit comments

Comments
 (0)