Skip to content
This repository has been archived by the owner on Jul 22, 2024. It is now read-only.

Crash service support #560

Merged
merged 11 commits into from
Oct 2, 2018
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package org.mozilla.vrbrowser;

import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Process;
import android.support.annotation.NonNull;
import android.support.v4.app.JobIntentService;
import android.util.Log;
import org.mozilla.geckoview.GeckoRuntime;

public class CrashReporterService extends JobIntentService {

private static final String LOGTAG = "VRB";

public static final String CRASH_ACTION = "org.mozilla.vrbrowser.CRASH_ACTION";
public static final String DATA_TAG = "intent";

private static final int PID_CHECK_INTERVAL = 100;
private static final int JOB_ID = 1000;

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(LOGTAG, "======> onStartCommand");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
enqueueWork(this, CrashReporterService.class, JOB_ID, intent);
}

return super.onStartCommand(intent, flags, startId);
}

@Override
protected void onHandleWork(@NonNull Intent intent) {
boolean fatal = false;
if (GeckoRuntime.ACTION_CRASHED.equals(intent.getAction())) {
fatal = intent.getBooleanExtra(GeckoRuntime.EXTRA_CRASH_FATAL, false);
}

if (fatal) {
Log.d(LOGTAG, "======> PARENT CRASH " + intent);
final int pid = Process.myPid();
final ActivityManager activityManager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
if (activityManager == null) {
return;
}

do {
boolean otherProcessesFound = false;
for (final ActivityManager.RunningAppProcessInfo info : activityManager.getRunningAppProcesses()) {
if (pid != info.pid) {
otherProcessesFound = true;
Log.e(LOGTAG, "======> Found PID " + info.pid);
break;
}
}

if (!otherProcessesFound) {
intent.setClass(CrashReporterService.this, VRBrowserActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
break;

} else {
try {
Thread.sleep(PID_CHECK_INTERVAL);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

} while (true);

} else {
Log.d(LOGTAG, "======> CONTENT CRASH " + intent);
Intent broadcastIntent = new Intent(CRASH_ACTION);
broadcastIntent.putExtra(DATA_TAG, intent);
sendBroadcast(broadcastIntent, getString(R.string.app_permission_name));
}

Log.d(LOGTAG, "======> Crash reporter job finished");
}

}
38 changes: 26 additions & 12 deletions app/src/common/shared/org/mozilla/vrbrowser/SessionStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ public interface SessionChangeListener {
void onCurrentSessionChange(GeckoSession aSession, int aId);
}

class SessionSettings {
boolean multiprocess = SettingsStore.getInstance(mContext).isMultiprocessEnabled();
boolean privateMode = false;
boolean trackingProtection = true;
boolean suspendMediaWhenInactive = true;
int userAgentMode = SettingsStore.getInstance(mContext).getUaMode();
}

class State {
boolean mCanGoBack;
boolean mCanGoForward;
Expand All @@ -64,6 +72,7 @@ class State {
String mTitle;
boolean mFullScreen;
GeckoSession mSession;
SessionSettings mSettings;
}

private GeckoRuntime mRuntime;
Expand Down Expand Up @@ -131,8 +140,7 @@ public void setContext(Context aContext, Bundle aExtras) {
// FIXME: Once GeckoView has a prefs API
vrPrefsWorkAround(aContext, aExtras);
GeckoRuntimeSettings.Builder runtimeSettingsBuilder = new GeckoRuntimeSettings.Builder();
// runtimeSettingsBuilder.javaCrashReportingEnabled(SettingsStore.getInstance(aContext).isCrashReportingEnabled());
// runtimeSettingsBuilder.nativeCrashReportingEnabled(SettingsStore.getInstance(aContext).isCrashReportingEnabled());
runtimeSettingsBuilder.crashHandler(CrashReporterService.class);
runtimeSettingsBuilder.trackingProtectionCategories(GeckoSession.TrackingProtectionDelegate.CATEGORY_AD | GeckoSession.TrackingProtectionDelegate.CATEGORY_SOCIAL | GeckoSession.TrackingProtectionDelegate.CATEGORY_ANALYTIC);
runtimeSettingsBuilder.consoleOutput(SettingsStore.getInstance(aContext).isConsoleLogsEnabled());
runtimeSettingsBuilder.displayDensityOverride(SettingsStore.getInstance(aContext).getDisplayDensity());
Expand Down Expand Up @@ -275,19 +283,12 @@ public void removePromptListener(GeckoSession.PromptDelegate aListener) {
mPromptListeners.remove(aListener);
}

public class SessionSettings {
public boolean multiprocess = SettingsStore.getInstance(mContext).isMultiprocessEnabled();
public boolean privateMode = false;
public boolean trackingProtection = true;
public boolean suspendMediaWhenInactive = true;
public int userAgentMode = SettingsStore.getInstance(mContext).getUaMode();
}

public int createSession() {
return createSession(new SessionSettings());
}
public int createSession(SessionSettings aSettings) {
int createSession(SessionSettings aSettings) {
State state = new State();
state.mSettings = aSettings;
state.mSession = new GeckoSession();

int result = state.mSession.hashCode();
Expand Down Expand Up @@ -318,6 +319,10 @@ public void removeSession(int aSessionId) {
session.setNavigationDelegate(null);
session.setProgressDelegate(null);
session.getTextInput().setDelegate(null);
session.setPromptDelegate(null);
session.setPermissionDelegate(null);
session.setTrackingProtectionDelegate(null);
session.close();
mSessions.remove(aSessionId);
for (SessionChangeListener listener: mSessionChangeListeners) {
listener.onRemoveSession(session, aSessionId);
Expand Down Expand Up @@ -937,7 +942,12 @@ public void onExternalResponse(GeckoSession session, GeckoSession.WebResponseInf

@Override
public void onCrash(GeckoSession session) {

Log.e(LOGTAG,"Child crashed. Creating new session");
int crashedSessionId = SessionStore.get().getCurrentSessionId();
int newSessionId = createSession();
setCurrentSession(newSessionId);
loadUri(getHomeUri());
removeSession(crashedSessionId);
}

// TextInput Delegate
Expand Down Expand Up @@ -1101,4 +1111,8 @@ public void onFilePrompt(GeckoSession session, String title, int type, String[]
}
}

@Override
public GeckoResult<Boolean> onPopupRequest(final GeckoSession session, final String targetUri) {
return GeckoResult.fromValue(false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@

package org.mozilla.vrbrowser;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.SurfaceTexture;
import android.net.Uri;
import android.opengl.GLES11Ext;
Expand All @@ -20,18 +23,33 @@
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import org.mozilla.gecko.GeckoVRManager;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.geckoview.CrashReporter;
import org.mozilla.geckoview.GeckoRuntime;
import org.mozilla.vrbrowser.audio.AudioEngine;
import org.mozilla.vrbrowser.audio.VRAudioTheme;
import org.mozilla.vrbrowser.search.SearchEngine;
import org.mozilla.vrbrowser.telemetry.TelemetryWrapper;
import org.mozilla.vrbrowser.ui.*;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;

public class VRBrowserActivity extends PlatformActivity implements WidgetManagerDelegate {

private BroadcastReceiver mCrashReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(CrashReporterService.CRASH_ACTION)) {
Intent crashIntent = intent.getParcelableExtra(CrashReporterService.DATA_TAG);
handleCrashIntent(crashIntent);
}
}
};

class SwipeRunnable implements Runnable {
boolean mCanceled = false;
@Override
Expand Down Expand Up @@ -65,6 +83,7 @@ public void run() {
BrowserWidget mBrowserWidget;
KeyboardWidget mKeyboard;
NavigationBarWidget mNavigationBar;
CrashDialogWidget mCrashDialog;
TopBarWidget mTopBar;
TrayWidget mTray;
PermissionDelegate mPermissionDelegate;
Expand All @@ -76,14 +95,19 @@ public void run() {

@Override
protected void onCreate(Bundle savedInstanceState) {
if (BuildConfig.FLAVOR == "oculusvr") {
if (BuildConfig.FLAVOR_platform == "oculusvr") {
workaroundGeckoSigAction();
}
mUiThread = Thread.currentThread();

Bundle extras = getIntent() != null ? getIntent().getExtras() : null;
SessionStore.get().setContext(this, extras);

// Create broadcast receiver for getting crash messages from crash process
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(CrashReporterService.CRASH_ACTION);
registerReceiver(mCrashReceiver, intentFilter, getString(R.string.app_permission_name), null);

mLastGesture = NoGesture;
super.onCreate(savedInstanceState);

Expand Down Expand Up @@ -199,6 +223,9 @@ protected void onResume() {

@Override
protected void onDestroy() {
// Unregister the crash service broadcast receiver
unregisterReceiver(mCrashReceiver);

for (Widget widget: mWidgets.values()) {
widget.releaseWidget();
}
Expand Down Expand Up @@ -227,14 +254,21 @@ protected void onNewIntent(final Intent intent) {
if (intent.getData() != null) {
loadFromIntent(intent);
}
} else if (GeckoRuntime.ACTION_CRASHED.equals(intent.getAction())) {
handleCrashIntent(intent);
}
}

void loadFromIntent(final Intent intent) {
if (GeckoRuntime.ACTION_CRASHED.equals(intent.getAction())) {
handleCrashIntent(intent);
}

Uri uri = intent.getData();
if (uri == null && intent.getExtras() != null && intent.getExtras().containsKey("url")) {
uri = Uri.parse(intent.getExtras().getString("url"));
}

if (SessionStore.get().getCurrentSession() == null) {
String url = (uri != null ? uri.toString() : null);
int id = SessionStore.get().createSession();
Expand All @@ -247,6 +281,50 @@ void loadFromIntent(final Intent intent) {
}
}

private void handleCrashIntent(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, "======> Dump Success: " +
intent.getBooleanExtra(GeckoRuntime.EXTRA_MINIDUMP_SUCCESS, false));
Log.d(LOGTAG, "======> Fatal: " +
intent.getBooleanExtra(GeckoRuntime.EXTRA_CRASH_FATAL, false));

boolean isCrashReportingEnabled = SettingsStore.getInstance(this).isCrashReportingEnabled();
if (isCrashReportingEnabled) {
sendCrashData(intent);

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

mCrashDialog.show();
}
}

private void sendCrashData(final Intent intent) {
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
try {
CrashReporter.sendCrashReport(VRBrowserActivity.this, intent, getString(R.string.crash_app_name));

} catch (IOException | URISyntaxException e) {
Log.e(LOGTAG, "Failed to send crash report: " + e.toString());
}
}
});
}

@Override
public void onBackPressed() {
if (mIsPresentingImmersive) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import org.mozilla.geckoview.GeckoDisplay;
import org.mozilla.geckoview.GeckoResult;
import org.mozilla.geckoview.GeckoSession;
import org.mozilla.geckoview.GeckoSessionSettings;
import org.mozilla.vrbrowser.*;
Expand Down Expand Up @@ -178,6 +179,7 @@ public void handleResizeEvent(float aWorldWidth, float aWorldHeight) {
@Override
public void releaseWidget() {
SessionStore.get().removeSessionChangeListener(this);
SessionStore.get().removePromptListener(this);
GeckoSession session = SessionStore.get().getSession(mSessionId);
if (session == null) {
return;
Expand Down Expand Up @@ -382,4 +384,9 @@ public void onDateTimePrompt(GeckoSession session, String title, int type, Strin
public void onFilePrompt(GeckoSession session, String title, int type, String[] mimeTypes, FileCallback callback) {

}

@Override
public GeckoResult<Boolean> onPopupRequest(final GeckoSession session, final String targetUri) {
return GeckoResult.fromValue(true);
}
}
Loading