mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
UWP: Crash report UI
This commit is contained in:
parent
0c00022ae0
commit
52f01a8a14
9 changed files with 196 additions and 36 deletions
|
@ -19,6 +19,7 @@ using namespace winrt::Windows::ApplicationModel::Resources;
|
|||
using namespace winrt::Windows::UI::Notifications;
|
||||
using namespace winrt::Windows::Data::Json;
|
||||
using namespace winrt::Windows::Data::Xml::Dom;
|
||||
using namespace winrt::Windows::Storage;
|
||||
using namespace winrt::servo;
|
||||
|
||||
namespace winrt::ServoApp::implementation {
|
||||
|
@ -37,15 +38,19 @@ void BrowserPage::BindServoEvents() {
|
|||
backButton().IsEnabled(back);
|
||||
forwardButton().IsEnabled(forward);
|
||||
});
|
||||
servoView().OnServoPanic([=](const auto &, hstring /*message*/) {
|
||||
mPanicking = true;
|
||||
CheckCrashReport();
|
||||
});
|
||||
servoView().OnLoadStarted([=] {
|
||||
urlbarLoadingIndicator().IsActive(true);
|
||||
transientLoadingIndicator().IsIndeterminate(true);
|
||||
|
||||
reloadButton().IsEnabled(false);
|
||||
reloadButton().Visibility(Visibility::Collapsed);
|
||||
stopButton().IsEnabled(true);
|
||||
stopButton().Visibility(Visibility::Visible);
|
||||
devtoolsButton().IsEnabled(true);
|
||||
CheckCrashReport();
|
||||
});
|
||||
servoView().OnLoadEnded([=] {
|
||||
urlbarLoadingIndicator().IsActive(false);
|
||||
|
@ -297,24 +302,59 @@ void BrowserPage::OnDevtoolsMessage(DevtoolsMessageLevel level, hstring source,
|
|||
});
|
||||
}
|
||||
|
||||
void BrowserPage::CheckCrashReport() {
|
||||
Concurrency::create_task([=] {
|
||||
auto pref = servo::Servo::GetPref(L"shell.crash_reporter.enabled");
|
||||
bool reporter_enabled = unbox_value<bool>(std::get<1>(pref));
|
||||
auto storageFolder = ApplicationData::Current().LocalFolder();
|
||||
bool file_exist =
|
||||
storageFolder.TryGetItemAsync(L"crash-report.txt").get() != nullptr;
|
||||
if (reporter_enabled && file_exist) {
|
||||
auto crash_file = storageFolder.GetFileAsync(L"crash-report.txt").get();
|
||||
auto content = FileIO::ReadTextAsync(crash_file).get();
|
||||
Dispatcher().RunAsync(CoreDispatcherPriority::High, [=] {
|
||||
auto resourceLoader = ResourceLoader::GetForCurrentView();
|
||||
auto message = resourceLoader.GetString(mPanicking ? L"crash/Happening"
|
||||
: L"crash/Happened");
|
||||
crashTabMessage().Text(message);
|
||||
crashReport().Text(content);
|
||||
crashTab().Visibility(Visibility::Visible);
|
||||
crashTab().IsSelected(true);
|
||||
ShowToolbox();
|
||||
});
|
||||
} else {
|
||||
Dispatcher().RunAsync(CoreDispatcherPriority::High, [=] {
|
||||
crashTab().Visibility(Visibility::Collapsed);
|
||||
devtoolsTabConsole().IsSelected(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void BrowserPage::OnDismissCrashReport(IInspectable const &,
|
||||
RoutedEventArgs const &) {
|
||||
Concurrency::create_task([=] {
|
||||
auto storageFolder = ApplicationData::Current().LocalFolder();
|
||||
auto crash_file = storageFolder.GetFileAsync(L"crash-report.txt").get();
|
||||
crash_file.DeleteAsync().get();
|
||||
});
|
||||
HideToolbox();
|
||||
}
|
||||
|
||||
void BrowserPage::OnSubmitCrashReport(IInspectable const &,
|
||||
RoutedEventArgs const &) {
|
||||
// FIXME
|
||||
}
|
||||
|
||||
void BrowserPage::OnDevtoolsDetached() {}
|
||||
|
||||
void BrowserPage::OnDevtoolsButtonClicked(IInspectable const &,
|
||||
RoutedEventArgs const &) {
|
||||
void BrowserPage::ShowToolbox() {
|
||||
if (toolbox().Visibility() == Visibility::Visible) {
|
||||
prefList().Children().Clear();
|
||||
toolbox().Visibility(Visibility::Collapsed);
|
||||
ClearConsole();
|
||||
if (mDevtoolsClient != nullptr) {
|
||||
mDevtoolsClient->Stop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
toolbox().Visibility(Visibility::Visible);
|
||||
|
||||
CheckCrashReport();
|
||||
BuildPrefList();
|
||||
|
||||
auto resourceLoader = ResourceLoader::GetForCurrentView();
|
||||
if (mDevtoolsStatus == DevtoolsStatus::Running) {
|
||||
hstring port = to_hstring(mDevtoolsPort);
|
||||
|
@ -337,6 +377,24 @@ void BrowserPage::OnDevtoolsButtonClicked(IInspectable const &,
|
|||
}
|
||||
}
|
||||
|
||||
void BrowserPage::HideToolbox() {
|
||||
prefList().Children().Clear();
|
||||
toolbox().Visibility(Visibility::Collapsed);
|
||||
ClearConsole();
|
||||
if (mDevtoolsClient != nullptr) {
|
||||
mDevtoolsClient->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserPage::OnDevtoolsButtonClicked(IInspectable const &,
|
||||
RoutedEventArgs const &) {
|
||||
if (toolbox().Visibility() == Visibility::Visible) {
|
||||
HideToolbox();
|
||||
} else {
|
||||
ShowToolbox();
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserPage::OnJSInputEdited(IInspectable const &,
|
||||
Input::KeyRoutedEventArgs const &e) {
|
||||
if (e.Key() == Windows::System::VirtualKey::Enter) {
|
||||
|
|
|
@ -41,6 +41,8 @@ public:
|
|||
void Shutdown();
|
||||
void LoadFXRURI(Uri uri);
|
||||
void SetArgs(hstring);
|
||||
void OnDismissCrashReport(IInspectable const &, RoutedEventArgs const &);
|
||||
void OnSubmitCrashReport(IInspectable const &, RoutedEventArgs const &);
|
||||
void OnMediaControlsPlayClicked(IInspectable const &,
|
||||
RoutedEventArgs const &);
|
||||
void OnMediaControlsPauseClicked(IInspectable const &,
|
||||
|
@ -55,11 +57,15 @@ public:
|
|||
private:
|
||||
void SetTransientMode(bool);
|
||||
void UpdatePref(ServoApp::Pref, Controls::Control);
|
||||
void CheckCrashReport();
|
||||
void BindServoEvents();
|
||||
void BuildPrefList();
|
||||
void ShowToolbox();
|
||||
void HideToolbox();
|
||||
DevtoolsStatus mDevtoolsStatus = DevtoolsStatus::Stopped;
|
||||
unsigned int mDevtoolsPort = 0;
|
||||
hstring mDevtoolsToken;
|
||||
bool mPanicking = false;
|
||||
std::unique_ptr<servo::DevtoolsClient> mDevtoolsClient;
|
||||
Collections::IObservableVector<IInspectable> mLogs;
|
||||
};
|
||||
|
|
|
@ -150,7 +150,7 @@
|
|||
</Button>
|
||||
</Grid>
|
||||
</muxc:TabView.TabStripFooter>
|
||||
<muxc:TabViewItem x:Uid="devtoolsTabConsole" IsClosable="False">
|
||||
<muxc:TabViewItem x:Uid="devtoolsTabConsole" x:Name="devtoolsTabConsole" IsClosable="False">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
|
@ -199,6 +199,20 @@
|
|||
</ScrollViewer>
|
||||
</Grid>
|
||||
</muxc:TabViewItem>
|
||||
<muxc:TabViewItem x:Uid="crashTab" x:Name="crashTab" IsClosable="False" Visibility="Collapsed">
|
||||
<Grid VerticalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Grid.Row="0" Padding="4" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" x:Name="crashTabMessage"></TextBlock>
|
||||
<Button IsTabStop="true" x:Uid="SubmitCrashReportButton" Margin="4" Click="OnSubmitCrashReport"/>
|
||||
<Button IsTabStop="true" x:Uid="DismissCrashReportButton" Margin="4" Click="OnDismissCrashReport"/>
|
||||
</StackPanel>
|
||||
<TextBox Grid.Row="1" TextWrapping="Wrap" IsTabStop="true" x:Name="crashReport" AcceptsReturn="True" IsSpellCheckEnabled="False" Margin="3"/>
|
||||
</Grid>
|
||||
</muxc:TabViewItem>
|
||||
</muxc:TabView>
|
||||
<ProgressBar x:Name="transientLoadingIndicator" Visibility="Collapsed" Grid.Row="3"/>
|
||||
<CommandBar Grid.Row="4" x:Name="mediaControls" Visibility="Collapsed">
|
||||
|
|
|
@ -21,8 +21,10 @@ void on_title_changed(const char *title) {
|
|||
sServo->Delegate().OnServoTitleChanged(char2hstring(title));
|
||||
}
|
||||
|
||||
void on_url_changed(const char *url) {
|
||||
sServo->Delegate().OnServoURLChanged(char2hstring(url));
|
||||
void on_url_changed(const char *curl) {
|
||||
auto url = char2hstring(curl);
|
||||
sServo->CurrentUrl(url);
|
||||
sServo->Delegate().OnServoURLChanged(url);
|
||||
}
|
||||
|
||||
void wakeup() { sServo->Delegate().WakeUp(); }
|
||||
|
@ -35,12 +37,46 @@ void on_animating_changed(bool aAnimating) {
|
|||
sServo->Delegate().OnServoAnimatingChanged(aAnimating);
|
||||
}
|
||||
|
||||
void on_panic(const char *backtrace) {
|
||||
void on_panic(const char *cbacktrace) {
|
||||
|
||||
if (sLogHandle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(sLogHandle);
|
||||
sLogHandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
throw hresult_error(E_FAIL, char2hstring(backtrace));
|
||||
|
||||
auto backtrace = char2hstring(cbacktrace);
|
||||
|
||||
try {
|
||||
// Making all sync operations sync, as we are crashing.
|
||||
auto storageFolder = ApplicationData::Current().LocalFolder();
|
||||
auto stdout_txt = storageFolder.GetFileAsync(L"stdout.txt").get();
|
||||
auto crash_txt =
|
||||
storageFolder
|
||||
.CreateFileAsync(L"crash-report.txt",
|
||||
CreationCollisionOption::ReplaceExisting)
|
||||
.get();
|
||||
auto out = FileIO::ReadTextAsync(stdout_txt).get();
|
||||
FileIO::WriteTextAsync(crash_txt, L"--- CUSTOM MESSAGE ---\r\n").get();
|
||||
FileIO::AppendTextAsync(crash_txt,
|
||||
L"Feel free to add details here before reporting")
|
||||
.get();
|
||||
FileIO::AppendTextAsync(
|
||||
crash_txt, L"\r\n--- CURRENT URL (remove if sensitive) ---\r\n")
|
||||
.get();
|
||||
FileIO::AppendTextAsync(crash_txt, sServo->CurrentUrl()).get();
|
||||
FileIO::AppendTextAsync(crash_txt, L"\r\n--- BACKTRACE ---\r\n").get();
|
||||
FileIO::AppendTextAsync(crash_txt, backtrace).get();
|
||||
FileIO::AppendTextAsync(crash_txt, L"\r\n--- STDOUT ---\r\n").get();
|
||||
FileIO::AppendTextAsync(crash_txt, out).get();
|
||||
FileIO::AppendTextAsync(crash_txt, L"\r\n").get();
|
||||
} catch (...) {
|
||||
log(L"Failed to log panic to crash report");
|
||||
}
|
||||
|
||||
// If this is happening in the GL thread, the app can continue running.
|
||||
// So let's show the crash report:
|
||||
sServo->Delegate().OnServoPanic(backtrace);
|
||||
throw hresult_error(E_FAIL, backtrace);
|
||||
}
|
||||
|
||||
void on_ime_show(const char *text, int32_t x, int32_t y, int32_t width,
|
||||
|
@ -371,9 +407,7 @@ std::vector<Servo::PrefTuple> Servo::GetPrefs() {
|
|||
return {};
|
||||
}
|
||||
auto prefs = capi::get_prefs();
|
||||
std::vector<
|
||||
std::tuple<hstring, winrt::Windows::Foundation::IInspectable, bool>>
|
||||
vec;
|
||||
std::vector<PrefTuple> vec;
|
||||
for (auto i = 0; i < prefs.len; i++) {
|
||||
auto pref = WrapPref(prefs.list[i]);
|
||||
vec.push_back(pref);
|
||||
|
|
|
@ -31,6 +31,8 @@ public:
|
|||
float, ServoDelegate &, bool);
|
||||
~Servo();
|
||||
ServoDelegate &Delegate() { return mDelegate; }
|
||||
hstring CurrentUrl() { return mUrl; }
|
||||
void CurrentUrl(hstring url) { mUrl = url; }
|
||||
|
||||
typedef std::tuple<hstring, winrt::Windows::Foundation::IInspectable, bool>
|
||||
PrefTuple;
|
||||
|
@ -96,6 +98,7 @@ public:
|
|||
|
||||
private:
|
||||
ServoDelegate &mDelegate;
|
||||
hstring mUrl;
|
||||
GLsizei mWindowWidth;
|
||||
GLsizei mWindowHeight;
|
||||
static void SaveUserPref(PrefTuple);
|
||||
|
@ -115,6 +118,7 @@ public:
|
|||
virtual void OnServoURLChanged(hstring) = 0;
|
||||
virtual bool OnServoAllowNavigation(hstring) = 0;
|
||||
virtual void OnServoAnimatingChanged(bool) = 0;
|
||||
virtual void OnServoPanic(hstring) = 0;
|
||||
virtual void OnServoIMEShow(hstring text, int32_t x, int32_t y, int32_t width,
|
||||
int32_t height) = 0;
|
||||
virtual void OnServoIMEHide() = 0;
|
||||
|
|
|
@ -418,34 +418,48 @@ void ServoControl::Loop() {
|
|||
|
||||
while (true) {
|
||||
EnterCriticalSection(&mGLLock);
|
||||
while (mTasks.size() == 0 && !mAnimating && mLooping) {
|
||||
SleepConditionVariableCS(&mGLCondVar, &mGLLock, INFINITE);
|
||||
}
|
||||
if (!mLooping) {
|
||||
try {
|
||||
while (mTasks.size() == 0 && !mAnimating && mLooping) {
|
||||
SleepConditionVariableCS(&mGLCondVar, &mGLLock, INFINITE);
|
||||
}
|
||||
if (!mLooping) {
|
||||
LeaveCriticalSection(&mGLLock);
|
||||
break;
|
||||
}
|
||||
for (auto &&task : mTasks) {
|
||||
task();
|
||||
}
|
||||
mTasks.clear();
|
||||
LeaveCriticalSection(&mGLLock);
|
||||
break;
|
||||
mServo->PerformUpdates();
|
||||
} catch (hresult_error const &e) {
|
||||
log(L"GL Thread exception: %s", e.message().c_str());
|
||||
throw e;
|
||||
} catch (...) {
|
||||
log(L"GL Thread exception");
|
||||
throw winrt::hresult_error(E_FAIL, L"GL Thread exception");
|
||||
}
|
||||
for (auto &&task : mTasks) {
|
||||
task();
|
||||
}
|
||||
mTasks.clear();
|
||||
LeaveCriticalSection(&mGLLock);
|
||||
mServo->PerformUpdates();
|
||||
}
|
||||
mServo->DeInit();
|
||||
}
|
||||
|
||||
void ServoControl::StartRenderLoop() {
|
||||
if (mLooping) {
|
||||
#if defined _DEBUG
|
||||
throw winrt::hresult_error(E_FAIL, L"GL thread is already looping");
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
mLooping = true;
|
||||
log(L"BrowserPage::StartRenderLoop(). UI thread: %i", GetCurrentThreadId());
|
||||
auto task = Concurrency::create_task([=] { Loop(); });
|
||||
auto task = Concurrency::create_task([=] {
|
||||
try {
|
||||
Loop();
|
||||
} catch (...) {
|
||||
// Do our best to recover. Exception has been logged at that point.
|
||||
mLooping = false;
|
||||
mLoopTask.reset();
|
||||
mServo.reset();
|
||||
LeaveCriticalSection(&mGLLock);
|
||||
}
|
||||
});
|
||||
mLoopTask = std::make_unique<Concurrency::task<void>>(task);
|
||||
}
|
||||
|
||||
|
@ -502,6 +516,10 @@ bool ServoControl::OnServoAllowNavigation(hstring uri) {
|
|||
return !mTransient;
|
||||
}
|
||||
|
||||
void ServoControl::OnServoPanic(hstring backtrace) {
|
||||
RunOnUIThread([=] { mOnServoPanic(*this, backtrace); });
|
||||
}
|
||||
|
||||
void ServoControl::OnServoAnimatingChanged(bool animating) {
|
||||
EnterCriticalSection(&mGLLock);
|
||||
mAnimating = animating;
|
||||
|
|
|
@ -100,6 +100,14 @@ struct ServoControl : ServoControlT<ServoControl>, public servo::ServoDelegate {
|
|||
mOnTitleChangedEvent.remove(token);
|
||||
}
|
||||
|
||||
winrt::event_token
|
||||
OnServoPanic(Windows::Foundation::EventHandler<hstring> const &handler) {
|
||||
return mOnServoPanic.add(handler);
|
||||
};
|
||||
void OnServoPanic(winrt::event_token const &token) noexcept {
|
||||
mOnServoPanic.remove(token);
|
||||
}
|
||||
|
||||
winrt::event_token OnHistoryChanged(HistoryChangedDelegate const &handler) {
|
||||
return mOnHistoryChangedEvent.add(handler);
|
||||
};
|
||||
|
@ -173,6 +181,7 @@ struct ServoControl : ServoControlT<ServoControl>, public servo::ServoDelegate {
|
|||
virtual void OnServoURLChanged(winrt::hstring);
|
||||
virtual bool OnServoAllowNavigation(winrt::hstring);
|
||||
virtual void OnServoAnimatingChanged(bool);
|
||||
virtual void OnServoPanic(hstring);
|
||||
virtual void OnServoIMEHide();
|
||||
virtual void OnServoIMEShow(hstring text, int32_t, int32_t, int32_t, int32_t);
|
||||
virtual void OnServoMediaSessionMetadata(winrt::hstring, winrt::hstring,
|
||||
|
@ -193,6 +202,7 @@ struct ServoControl : ServoControlT<ServoControl>, public servo::ServoDelegate {
|
|||
private:
|
||||
winrt::event<Windows::Foundation::EventHandler<hstring>> mOnURLChangedEvent;
|
||||
winrt::event<Windows::Foundation::EventHandler<hstring>> mOnTitleChangedEvent;
|
||||
winrt::event<Windows::Foundation::EventHandler<hstring>> mOnServoPanic;
|
||||
winrt::event<HistoryChangedDelegate> mOnHistoryChangedEvent;
|
||||
winrt::event<DevtoolsStatusChangedDelegate> mOnDevtoolsStatusChangedEvent;
|
||||
winrt::event<EventDelegate> mOnLoadStartedEvent;
|
||||
|
|
|
@ -39,6 +39,7 @@ namespace ServoApp {
|
|||
event DevtoolsStatusChangedDelegate OnDevtoolsStatusChanged;
|
||||
event HistoryChangedDelegate OnHistoryChanged;
|
||||
event Windows.Foundation.EventHandler<String> OnTitleChanged;
|
||||
event Windows.Foundation.EventHandler<String> OnServoPanic;
|
||||
event Windows.Foundation.EventHandler<String> OnURLChanged;
|
||||
event MediaSessionMetadataDelegate OnMediaSessionMetadata;
|
||||
event Windows.Foundation.EventHandler<int> OnMediaSessionPlaybackStateChange;
|
||||
|
|
|
@ -114,6 +114,21 @@
|
|||
<data name="devtoolsTabPrefs.[using:Microsoft.UI.Xaml.Controls]TabViewItem.Header" xml:space="preserve">
|
||||
<value>Preferences</value>
|
||||
</data>
|
||||
<data name="crashTab.[using:Microsoft.UI.Xaml.Controls]TabViewItem.Header" xml:space="preserve">
|
||||
<value>Crash Report</value>
|
||||
</data>
|
||||
<data name="crash.Happening" xml:space="preserve">
|
||||
<value>Internal crash detected. Application might be unstable:</value>
|
||||
</data>
|
||||
<data name="crash.Happened" xml:space="preserve">
|
||||
<value>Internal crash was detected during last run:</value>
|
||||
</data>
|
||||
<data name="SubmitCrashReportButton.Content" xml:space="preserve">
|
||||
<value>Send crash report</value>
|
||||
</data>
|
||||
<data name="DismissCrashReportButton.Content" xml:space="preserve">
|
||||
<value>Dismiss</value>
|
||||
</data>
|
||||
<data name="preferenceSearchbox.PlaceholderText" xml:space="preserve">
|
||||
<value>Search Preferences</value>
|
||||
</data>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue