Skip to content
Permalink
Browse files

Write a file containing the crash files location. Fixes #1846 (#1847)

  • Loading branch information...
bluemarvin committed Sep 17, 2019
1 parent 5d08acb commit e984058749aed154c7359076090b6d5c0919474d
@@ -72,8 +72,14 @@
import org.mozilla.vrbrowser.utils.ServoUtils;
import org.mozilla.vrbrowser.utils.SystemUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
@@ -88,7 +94,7 @@
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(CrashReporterService.CRASH_ACTION)) {
Intent crashIntent = intent.getParcelableExtra(CrashReporterService.DATA_TAG);
handleCrashIntent(crashIntent);
handleContentCrashIntent(crashIntent);
}
}
};
@@ -113,6 +119,7 @@ public void run() {
static final int GestureSwipeRight = 1;
static final int SwipeDelay = 1000; // milliseconds
static final long RESET_CRASH_COUNT_DELAY = 5000;
static final String CRASH_STATS_URL = "https://crash-stats.mozilla.com/report/index/";

static final String LOGTAG = SystemUtils.createLogtag(VRBrowserActivity.class);
HashMap<Integer, Widget> mWidgets;
@@ -255,6 +262,7 @@ protected void onCreate(Bundle savedInstanceState) {

mConnectivityReceiver = new ConnectivityReceiver();
mPoorPerformanceWhiteList = new HashSet<>();
checkForCrash();
}

protected void initializeWidgets() {
@@ -420,7 +428,7 @@ protected void onNewIntent(final Intent intent) {
loadFromIntent(intent);
}
} else if (GeckoRuntime.ACTION_CRASHED.equals(intent.getAction())) {
handleCrashIntent(intent);
Log.e(LOGTAG, "Restarted after a crash");
}
}

@@ -433,7 +441,7 @@ public void onConfigurationChanged(Configuration newConfig) {

void loadFromIntent(final Intent intent) {
if (GeckoRuntime.ACTION_CRASHED.equals(intent.getAction())) {
handleCrashIntent(intent);
Log.e(LOGTAG,"Loading from crash Intent");
}

Uri uri = intent.getData();
@@ -481,44 +489,104 @@ private void handleConnectivityChange() {
mConnectionAvailable = connected;
}

private void handleCrashIntent(@NonNull final Intent intent) {
Log.e(LOGTAG, "======> Got crashed intent");
Log.d(LOGTAG, "======> Dump File: " +
intent.getStringExtra(GeckoRuntime.EXTRA_MINIDUMP_PATH));
Log.d(LOGTAG, "======> Extras File: " +
intent.getStringExtra(GeckoRuntime.EXTRA_EXTRAS_PATH));
Log.d(LOGTAG, "======> Fatal: " +
intent.getBooleanExtra(GeckoRuntime.EXTRA_CRASH_FATAL, false));

private void checkForCrash() {
final ArrayList<String> files = CrashReporterService.findCrashFiles(getBaseContext());
if (files.isEmpty()) {
Log.d(LOGTAG, "No crash files found.");
return;
}
boolean isCrashReportingEnabled = SettingsStore.getInstance(this).isCrashReportingEnabled();
if (isCrashReportingEnabled) {
sendCrashData(intent);

postCrashFiles(files);
} else {
if (mCrashDialog == null) {
mCrashDialog = new CrashDialogWidget(this);
mCrashDialog.setCrashDialogDelegate(() -> sendCrashData(intent));
}
mCrashDialog.setCrashDialogDelegate(
new CrashDialogWidget.CrashDialogDelegate() {
@Override
public void onSendData() {
postCrashFiles(files);
}

@Override
public void onDoNotSendData() {
for (String file : files) {
Log.e(LOGTAG, "Deleting crashfile: " + file);
getBaseContext().deleteFile(file);
}
}
}
);
mCrashDialog.show(UIWidget.REQUEST_FOCUS);
}
}

private void sendCrashData(final Intent intent) {
private void handleContentCrashIntent(@NonNull final Intent intent) {
Log.e(LOGTAG, "Got content crashed intent");
final String dumpFile = intent.getStringExtra(GeckoRuntime.EXTRA_MINIDUMP_PATH);
final String extraFile = intent.getStringExtra(GeckoRuntime.EXTRA_EXTRAS_PATH);
Log.d(LOGTAG, "Dump File: " + dumpFile);
Log.d(LOGTAG, "Extras File: " + extraFile);
Log.d(LOGTAG, "Fatal: " + intent.getBooleanExtra(GeckoRuntime.EXTRA_CRASH_FATAL, false));

boolean isCrashReportingEnabled = SettingsStore.getInstance(this).isCrashReportingEnabled();
if (isCrashReportingEnabled) {
postCrashFiles(dumpFile, extraFile);
} else {
if (mCrashDialog == null) {
mCrashDialog = new CrashDialogWidget(this);
}
mCrashDialog.setCrashDialogDelegate(() -> postCrashFiles(dumpFile, extraFile));
mCrashDialog.show(UIWidget.REQUEST_FOCUS);
}
}

private void sendCrashFiles(@NonNull final String aDumpFile, @NonNull final String aExtraFile) {
try {
GeckoResult<String> result = CrashReporter.sendCrashReport(VRBrowserActivity.this, new File(aDumpFile), new File(aExtraFile), getString(R.string.crash_app_name));

result.accept(crashID -> {
Log.e(LOGTAG, "Submitted crash report id: " + crashID);
Log.e(LOGTAG, "Report available at: " + CRASH_STATS_URL + crashID);
}, ex -> {
Log.e(LOGTAG, "Failed to submit crash report: " + (ex != null ? ex.getMessage() : "Exception is NULL"));
});
} catch (IOException | URISyntaxException e) {
Log.e(LOGTAG, "Failed to send crash report: " + e.toString());
}
}

private void postCrashFiles(@NonNull final String aDumpFile, @NonNull final String aExtraFile) {
ThreadUtils.postToBackgroundThread(() -> {
try {
GeckoResult<String> result = CrashReporter.sendCrashReport(VRBrowserActivity.this, intent, getString(R.string.crash_app_name));

result.then(crashID -> {
Log.e(LOGTAG, "Submitted crash report id: " + crashID);
Log.e(LOGTAG, "Report available at: https://crash-stats.mozilla.com/report/index/" + crashID);
return null;
}, (GeckoResult.OnExceptionListener<Void>) ex -> {
Log.e(LOGTAG, "Failed to submit crash report: " + ex.getMessage());
return null;
});
} catch (IOException | URISyntaxException e) {
Log.e(LOGTAG, "Failed to send crash report: " + e.toString());
sendCrashFiles(aDumpFile, aExtraFile);
});
}

private void postCrashFiles(final ArrayList<String> aFiles) {
ThreadUtils.postToBackgroundThread(() -> {
for (String file: aFiles) {
try {
ArrayList<String> list = new ArrayList<>(2);
try (FileInputStream in = getBaseContext().openFileInput(file)) {
try(BufferedReader br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
String line;
while((line = br.readLine()) != null) {
list.add(line);
}
}
} catch (IOException e) {
e.printStackTrace();
}
if (list.size() < 2) {
Log.e(LOGTAG, "Failed read crash dump file names from: " + file);
return;
}
sendCrashFiles(list.get(0), list.get(1));
} finally {
Log.d(LOGTAG,"Removing crash file: " + file);
getBaseContext().deleteFile(file);
}
}
});
}
@@ -4,7 +4,6 @@
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Process;
import android.util.Log;

import org.mozilla.geckoview.GeckoRuntime;
@@ -14,6 +13,12 @@
import org.mozilla.vrbrowser.browser.SettingsStore;
import org.mozilla.vrbrowser.utils.SystemUtils;


import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.UUID;

import androidx.annotation.NonNull;
import androidx.core.app.JobIntentService;

@@ -23,6 +28,7 @@

public static final String CRASH_ACTION = BuildConfig.APPLICATION_ID + ".CRASH_ACTION";
public static final String DATA_TAG = "intent";
public static final String CRASH_FILE_PREFIX = "crashfile-";

private static final int PID_CHECK_INTERVAL = 100;
private static final int JOB_ID = 1000;
@@ -41,13 +47,24 @@ public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}

@NonNull
public static ArrayList<String> findCrashFiles(@NonNull Context aContext) {
ArrayList<String> files = new ArrayList<>();
String[] allFiles = aContext.fileList();
for (String value: allFiles) {
if (value.startsWith(CRASH_FILE_PREFIX)) {
files.add(value);
}
}
return files;
}

@Override
protected void onHandleWork(@NonNull Intent intent) {
String action = intent.getAction();
if (GeckoRuntime.ACTION_CRASHED.equals(action)) {
final int activityPid = SettingsStore.getInstance(getBaseContext()).getPid();
boolean fatal = intent.getBooleanExtra(GeckoRuntime.EXTRA_CRASH_FATAL, false);

long count = SettingsStore.getInstance(getBaseContext()).getCrashRestartCount();
boolean cancelRestart = count > MAX_RESTART_COUNT;
if (cancelRestart || BuildConfig.DISABLE_CRASH_RESTART) {
@@ -57,6 +74,16 @@ protected void onHandleWork(@NonNull Intent intent) {

if (fatal) {
Log.d(LOGTAG, "Main process crash " + intent);
final String dumpFile = intent.getStringExtra(GeckoRuntime.EXTRA_MINIDUMP_PATH) + "\n";
final String extraFile = intent.getStringExtra(GeckoRuntime.EXTRA_EXTRAS_PATH);
final String crashFile = CRASH_FILE_PREFIX + UUID.randomUUID().toString().replaceAll("-", "") + ".txt";
try (FileOutputStream file = getBaseContext().openFileOutput(crashFile, 0)) {
file.write(dumpFile.getBytes());
file.write(extraFile.getBytes());
Log.d(LOGTAG, "Wrote crashfile: " + crashFile);
} catch (IOException e) {
Log.e(LOGTAG, "Failed to create crash file: '" + crashFile + "' error: " + e.getMessage());
}
if (activityPid == 0) {
Log.e(LOGTAG, "Application was quitting. Crash reporter will not trigger a restart.");
return;
@@ -74,6 +101,8 @@ protected void onHandleWork(@NonNull Intent intent) {
activityFound = true;
Log.e(LOGTAG, "Main activity still running: " + activityPid);
break;
} else {
Log.d(LOGTAG, "Main activity not found: " + activityPid);
}
}

@@ -17,12 +17,12 @@
import org.mozilla.vrbrowser.browser.SettingsStore;
import org.mozilla.vrbrowser.ui.widgets.WidgetManagerDelegate;
import org.mozilla.vrbrowser.ui.widgets.WidgetPlacement;
import org.mozilla.vrbrowser.utils.SystemUtils;

public class CrashDialogWidget extends UIDialog {

public interface CrashDialogDelegate {
void onSendData();
default void onDoNotSendData() {}
}

private Button mLearnMoreButton;
@@ -74,6 +74,9 @@ private void initialize(Context aContext) {
mAudio.playSound(AudioEngine.Sound.CLICK);
}

if(mCrashDialogDelegate != null) {
mCrashDialogDelegate.onDoNotSendData();
}
onDismiss();
});

0 comments on commit e984058

Please sign in to comment.
You can’t perform that action at this time.