diff options
author | Paul Rouget <me@paulrouget.com> | 2020-08-03 17:23:30 +0200 |
---|---|---|
committer | Paul Rouget <me@paulrouget.com> | 2020-08-03 17:36:52 +0200 |
commit | 52f01a8a1491584f0f8915fbcd4f1473a3fe64bf (patch) | |
tree | 5670e3a31760888d92b96109f6833a2c649c77c9 /support | |
parent | 0c00022ae04d9116c4a31b389fc03d843ff368bd (diff) | |
download | servo-52f01a8a1491584f0f8915fbcd4f1473a3fe64bf.tar.gz servo-52f01a8a1491584f0f8915fbcd4f1473a3fe64bf.zip |
UWP: Crash report UI
Diffstat (limited to 'support')
-rw-r--r-- | support/hololens/ServoApp/BrowserPage.cpp | 82 | ||||
-rw-r--r-- | support/hololens/ServoApp/BrowserPage.h | 6 | ||||
-rw-r--r-- | support/hololens/ServoApp/BrowserPage.xaml | 16 | ||||
-rw-r--r-- | support/hololens/ServoApp/ServoControl/Servo.cpp | 48 | ||||
-rw-r--r-- | support/hololens/ServoApp/ServoControl/Servo.h | 4 | ||||
-rw-r--r-- | support/hololens/ServoApp/ServoControl/ServoControl.cpp | 50 | ||||
-rw-r--r-- | support/hololens/ServoApp/ServoControl/ServoControl.h | 10 | ||||
-rw-r--r-- | support/hololens/ServoApp/ServoControl/ServoControl.idl | 1 | ||||
-rw-r--r-- | support/hololens/ServoApp/Strings/en-US/Resources.resw | 15 |
9 files changed, 196 insertions, 36 deletions
diff --git a/support/hololens/ServoApp/BrowserPage.cpp b/support/hololens/ServoApp/BrowserPage.cpp index 095617f6dea..d3f738427c6 100644 --- a/support/hololens/ServoApp/BrowserPage.cpp +++ b/support/hololens/ServoApp/BrowserPage.cpp @@ -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) { diff --git a/support/hololens/ServoApp/BrowserPage.h b/support/hololens/ServoApp/BrowserPage.h index 2f800a516ac..a5ad43b4286 100644 --- a/support/hololens/ServoApp/BrowserPage.h +++ b/support/hololens/ServoApp/BrowserPage.h @@ -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; }; diff --git a/support/hololens/ServoApp/BrowserPage.xaml b/support/hololens/ServoApp/BrowserPage.xaml index 9b73f29527b..d85947b8807 100644 --- a/support/hololens/ServoApp/BrowserPage.xaml +++ b/support/hololens/ServoApp/BrowserPage.xaml @@ -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"> diff --git a/support/hololens/ServoApp/ServoControl/Servo.cpp b/support/hololens/ServoApp/ServoControl/Servo.cpp index 3496610ed86..4e3eeedf981 100644 --- a/support/hololens/ServoApp/ServoControl/Servo.cpp +++ b/support/hololens/ServoApp/ServoControl/Servo.cpp @@ -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); diff --git a/support/hololens/ServoApp/ServoControl/Servo.h b/support/hololens/ServoApp/ServoControl/Servo.h index db2ade2e14e..fb2c2f5fb22 100644 --- a/support/hololens/ServoApp/ServoControl/Servo.h +++ b/support/hololens/ServoApp/ServoControl/Servo.h @@ -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; diff --git a/support/hololens/ServoApp/ServoControl/ServoControl.cpp b/support/hololens/ServoApp/ServoControl/ServoControl.cpp index 9898f0ea258..b2ff048248f 100644 --- a/support/hololens/ServoApp/ServoControl/ServoControl.cpp +++ b/support/hololens/ServoApp/ServoControl/ServoControl.cpp @@ -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; - } - for (auto &&task : mTasks) { - task(); + 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"); } - 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; diff --git a/support/hololens/ServoApp/ServoControl/ServoControl.h b/support/hololens/ServoApp/ServoControl/ServoControl.h index bf53f0e6487..be1f8090776 100644 --- a/support/hololens/ServoApp/ServoControl/ServoControl.h +++ b/support/hololens/ServoApp/ServoControl/ServoControl.h @@ -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; diff --git a/support/hololens/ServoApp/ServoControl/ServoControl.idl b/support/hololens/ServoApp/ServoControl/ServoControl.idl index 33e7629170c..fe83d535322 100644 --- a/support/hololens/ServoApp/ServoControl/ServoControl.idl +++ b/support/hololens/ServoApp/ServoControl/ServoControl.idl @@ -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; diff --git a/support/hololens/ServoApp/Strings/en-US/Resources.resw b/support/hololens/ServoApp/Strings/en-US/Resources.resw index 86b9d2558e4..717ffbff23b 100644 --- a/support/hololens/ServoApp/Strings/en-US/Resources.resw +++ b/support/hololens/ServoApp/Strings/en-US/Resources.resw @@ -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> |