From 123247956b63c257829b64f2c51303aedd2367b4 Mon Sep 17 00:00:00 2001 From: "Randall E. Barker" Date: Wed, 17 Jul 2019 10:19:17 -0700 Subject: [PATCH] Add support for performance monitor (#1401) * Add support for performance monitor. * Add performance monitor switch to developer options --- .../mozilla/vrbrowser/VRBrowserActivity.java | 36 ++++++++++++ .../vrbrowser/browser/SettingsStore.java | 11 ++++ .../vrbrowser/ui/widgets/WindowWidget.java | 10 ++++ .../settings/DeveloperOptionsView.java | 17 ++++++ app/src/main/cpp/BrowserWorld.cpp | 25 +++++++++ app/src/main/cpp/VRBrowser.cpp | 56 +++++++++++-------- app/src/main/cpp/VRBrowser.h | 1 + app/src/main/cpp/vrb | 2 +- app/src/main/res/layout/options_developer.xml | 6 ++ app/src/main/res/values/non_L10n.xml | 1 + app/src/main/res/values/strings.xml | 13 +++++ 11 files changed, 154 insertions(+), 24 deletions(-) diff --git a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java index 2f731016e..15bd03556 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java @@ -69,7 +69,9 @@ import java.net.URISyntaxException; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; +import java.util.Set; import java.util.function.Consumer; import androidx.annotation.IntDef; @@ -144,6 +146,7 @@ public void run() { private boolean mConnectionAvailable = true; private AudioManager mAudioManager; private Widget mActiveDialog; + private Set mPoorPerformanceWhiteList; private boolean callOnAudioManager(Consumer fn) { if (mAudioManager == null) { @@ -243,6 +246,7 @@ protected void onCreate(Bundle savedInstanceState) { GeolocationWrapper.update(this); mConnectivityReceiver = new ConnectivityReceiver(); + mPoorPerformanceWhiteList = new HashSet<>(); } protected void initializeWorld() { @@ -852,6 +856,38 @@ public void dismiss() { }); } + @Keep + @SuppressWarnings("unused") + private void handlePoorPerformance() { + runOnUiThread(() -> { + if (!mSettings.isPerformanceMonitorEnabled()) { + return; + } + // Don't block poorly performing immersive pages. + if (mIsPresentingImmersive) { + return; + } + if (mWindowWidget == null) { + return; + } + final String originalUrl = SessionStore.get().getCurrentUri(); + if (mPoorPerformanceWhiteList.contains(originalUrl)) { + return; + } + SessionStore.get().loadUri("about:blank"); + final String[] buttons = {getString(R.string.ok_button), null, getString(R.string.performance_unblock_page)}; + mWindowWidget.showButtonPrompt(getString(R.string.performance_title), getString(R.string.performance_message), buttons, new GeckoSession.PromptDelegate.ButtonCallback() { + @Override + public void confirm(int button) { + if (button == 0) { + mPoorPerformanceWhiteList.add(originalUrl); + SessionStore.get().loadUri(originalUrl); + } + } + }); + }); + } + void createOffscreenDisplay() { int[] ids = new int[1]; GLES20.glGenTextures(1, ids, 0); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java index 90241c842..b786ae7bb 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java @@ -44,6 +44,7 @@ SettingsStore getInstance(final @NonNull Context aContext) { public final static boolean CONSOLE_LOGS_DEFAULT = false; public final static boolean ENV_OVERRIDE_DEFAULT = false; public final static boolean MULTIPROCESS_DEFAULT = false; + public final static boolean PERFORMANCE_MONITOR_DEFAULT = true; public final static boolean TRACKING_DEFAULT = true; public final static boolean SERVO_DEFAULT = false; public final static int UA_MODE_DEFAULT = GeckoSessionSettings.USER_AGENT_MODE_VR; @@ -179,6 +180,16 @@ public void setMultiprocessEnabled(boolean isEnabled) { editor.commit(); } + public boolean isPerformanceMonitorEnabled() { + return mPrefs.getBoolean(mContext.getString(R.string.settings_key_performance_monitor), PERFORMANCE_MONITOR_DEFAULT); + } + + public void setPerformanceMonitorEnabled(boolean isEnabled) { + SharedPreferences.Editor editor = mPrefs.edit(); + editor.putBoolean(mContext.getString(R.string.settings_key_performance_monitor), isEnabled); + editor.commit(); + } + public boolean isServoEnabled() { return isServoAvailable() && mPrefs.getBoolean(mContext.getString(R.string.settings_key_servo), SERVO_DEFAULT); } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java index cc5c91a42..97dea4bd3 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java @@ -598,6 +598,16 @@ public void showAlert(String title, @NonNull String msg, @NonNull AlertCallback mAlertPrompt.show(REQUEST_FOCUS); } + public void showButtonPrompt(String title, @NonNull String msg, @NonNull String[] btnMsg, @NonNull ButtonCallback callback) { + mConfirmPrompt = new ConfirmPromptWidget(getContext()); + mConfirmPrompt.mWidgetPlacement.parentHandle = getHandle(); + mConfirmPrompt.setTitle(title); + mConfirmPrompt.setMessage(msg); + mConfirmPrompt.setButtons(btnMsg); + mConfirmPrompt.setDelegate(callback); + mConfirmPrompt.show(REQUEST_FOCUS); + } + // PromptDelegate @Override diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/DeveloperOptionsView.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/DeveloperOptionsView.java index 81d99d59e..4d04317c6 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/DeveloperOptionsView.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/settings/DeveloperOptionsView.java @@ -27,6 +27,7 @@ class DeveloperOptionsView extends SettingsView { private SwitchSetting mRemoteDebuggingSwitch; private SwitchSetting mConsoleLogsSwitch; private SwitchSetting mMultiprocessSwitch; + private SwitchSetting mPerformanceSwitch; private SwitchSetting mServoSwitch; private SingleEditSetting mHomepageEdit; private String mDefaultHomepageUrl; @@ -73,6 +74,10 @@ private void initialize(Context aContext) { mMultiprocessSwitch.setOnCheckedChangeListener(mMultiprocessListener); setMultiprocess(SettingsStore.getInstance(getContext()).isMultiprocessEnabled(), false); + mPerformanceSwitch = findViewById(R.id.performance_monitor_switch); + mPerformanceSwitch.setOnCheckedChangeListener(mPerformanceListener); + setPerformance(SettingsStore.getInstance(getContext()).isPerformanceMonitorEnabled(), false); + mServoSwitch = findViewById(R.id.servo_switch); if (!isServoAvailable()) { mServoSwitch.setVisibility(View.GONE); @@ -130,6 +135,10 @@ protected void onDismiss() { setMultiprocess(value, doApply); }; + private SwitchSetting.OnCheckedChangeListener mPerformanceListener = (compoundButton, value, doApply) -> { + setPerformance(value, doApply); + }; + private SwitchSetting.OnCheckedChangeListener mServoListener = (compoundButton, b, doApply) -> { setServo(b, true); }; @@ -200,6 +209,14 @@ private void setMultiprocess(boolean value, boolean doApply) { } } + private void setPerformance(boolean value, boolean doApply) { + mPerformanceSwitch.setOnCheckedChangeListener(null); + mPerformanceSwitch.setValue(value, false); + mPerformanceSwitch.setOnCheckedChangeListener(mPerformanceListener); + + SettingsStore.getInstance(getContext()).setPerformanceMonitorEnabled(value); + } + private void setServo(boolean value, boolean doApply) { mServoSwitch.setOnCheckedChangeListener(null); mServoSwitch.setValue(value, false); diff --git a/app/src/main/cpp/BrowserWorld.cpp b/app/src/main/cpp/BrowserWorld.cpp index 290f9cce6..596944179 100644 --- a/app/src/main/cpp/BrowserWorld.cpp +++ b/app/src/main/cpp/BrowserWorld.cpp @@ -39,6 +39,7 @@ #include "vrb/ModelLoaderAndroid.h" #include "vrb/NodeFactoryObj.h" #include "vrb/ParserObj.h" +#include "vrb/PerformanceMonitor.h" #include "vrb/RenderContext.h" #include "vrb/RenderState.h" #include "vrb/SurfaceTextureFactory.h" @@ -118,6 +119,25 @@ SurfaceObserver::SurfaceTextureCreationError(const std::string& aName, const std } +class PerformanceObserver; +typedef std::shared_ptr PerformanceObserverPtr; + +class PerformanceObserver : public PerformanceMonitorObserver { +public: + void PoorPerformanceDetected(const double& aTargetFrameRate, const double& aAverageFrameRate) override; + void PerformanceRestored(const double& aTargetFrameRate, const double& aAverageFrameRate) override; +}; + +void +PerformanceObserver::PoorPerformanceDetected(const double& aTargetFrameRate, const double& aAverageFrameRate) { + crow::VRBrowser::HandlePoorPerformance(); +} + +void +PerformanceObserver::PerformanceRestored(const double& aTargetFrameRate, const double& aAverageFrameRate) { + +} + } // namespace namespace crow { @@ -160,6 +180,7 @@ struct BrowserWorld::State { LoadingAnimationPtr loadingAnimation; SplashAnimationPtr splashAnimation; VRVideoPtr vrVideo; + PerformanceMonitorPtr monitor; State() : paused(true), glInitialized(false), modelsLoaded(false), env(nullptr), cylinderDensity(0.0f), nearClip(0.1f), farClip(300.0f), activity(nullptr), windowsInitialized(false), exitImmersiveRequested(false), loaderDelay(0) { @@ -183,6 +204,8 @@ struct BrowserWorld::State { fadeAnimation = FadeAnimation::Create(create); loadingAnimation = LoadingAnimation::Create(create); splashAnimation = SplashAnimation::Create(create); + monitor = PerformanceMonitor::Create(create); + monitor->AddPerformanceMonitorObserver(std::make_shared()); } void CheckBackButton(); @@ -540,12 +563,14 @@ void BrowserWorld::Pause() { ASSERT_ON_RENDER_THREAD(); m.paused = true; + m.monitor->Pause(); } void BrowserWorld::Resume() { ASSERT_ON_RENDER_THREAD(); m.paused = false; + m.monitor->Resume(); } bool diff --git a/app/src/main/cpp/VRBrowser.cpp b/app/src/main/cpp/VRBrowser.cpp index a44dea145..009164fba 100644 --- a/app/src/main/cpp/VRBrowser.cpp +++ b/app/src/main/cpp/VRBrowser.cpp @@ -48,29 +48,32 @@ const char* kSetDeviceType = "setDeviceType"; const char* kSetDeviceTypeSignature = "(I)V"; const char* kHaltActivity = "haltActivity"; const char* kHaltActivitySignature = "(I)V"; - -JNIEnv* sEnv; -jclass sBrowserClass; -jobject sActivity; -jmethodID sDispatchCreateWidget; -jmethodID sDispatchCreateWidgetLayer; -jmethodID sHandleMotionEvent; -jmethodID sHandleScrollEvent; -jmethodID sHandleAudioPose; -jmethodID sHandleGesture; -jmethodID sHandleResize; -jmethodID sHandleBack; -jmethodID sRegisterExternalContext; -jmethodID sPauseCompositor; -jmethodID sResumeCompositor; -jmethodID sRenderPointerLayer; -jmethodID sGetStorageAbsolutePath; -jmethodID sIsOverrideEnvPathEnabled; -jmethodID sGetActiveEnvironment; -jmethodID sGetPointerColor; -jmethodID sAreLayersEnabled; -jmethodID sSetDeviceType; -jmethodID sHaltActivity; +const char* kHandlePoorPerformance = "handlePoorPerformance"; +const char* kHandlePoorPerformanceSignature = "()V"; + +JNIEnv* sEnv = nullptr; +jclass sBrowserClass = nullptr; +jobject sActivity = nullptr; +jmethodID sDispatchCreateWidget = nullptr; +jmethodID sDispatchCreateWidgetLayer = nullptr; +jmethodID sHandleMotionEvent = nullptr; +jmethodID sHandleScrollEvent = nullptr; +jmethodID sHandleAudioPose = nullptr; +jmethodID sHandleGesture = nullptr; +jmethodID sHandleResize = nullptr; +jmethodID sHandleBack = nullptr; +jmethodID sRegisterExternalContext = nullptr; +jmethodID sPauseCompositor = nullptr; +jmethodID sResumeCompositor = nullptr; +jmethodID sRenderPointerLayer = nullptr; +jmethodID sGetStorageAbsolutePath = nullptr; +jmethodID sIsOverrideEnvPathEnabled = nullptr; +jmethodID sGetActiveEnvironment = nullptr; +jmethodID sGetPointerColor = nullptr; +jmethodID sAreLayersEnabled = nullptr; +jmethodID sSetDeviceType = nullptr; +jmethodID sHaltActivity = nullptr; +jmethodID sHandlePoorPerformance = nullptr; } namespace crow { @@ -109,6 +112,7 @@ VRBrowser::InitializeJava(JNIEnv* aEnv, jobject aActivity) { sAreLayersEnabled = FindJNIMethodID(sEnv, sBrowserClass, kAreLayersEnabled, kAreLayersEnabledSignature); sSetDeviceType = FindJNIMethodID(sEnv, sBrowserClass, kSetDeviceType, kSetDeviceTypeSignature); sHaltActivity = FindJNIMethodID(sEnv, sBrowserClass, kHaltActivity, kHaltActivitySignature); + sHandlePoorPerformance = FindJNIMethodID(sEnv, sBrowserClass, kHandlePoorPerformance, kHandlePoorPerformanceSignature); } void @@ -316,5 +320,11 @@ VRBrowser::HaltActivity(const jint aReason) { CheckJNIException(sEnv, __FUNCTION__); } +void +VRBrowser::HandlePoorPerformance() { + if (!ValidateMethodID(sEnv, sActivity, sHandlePoorPerformance, __FUNCTION__)) { return; } + sEnv->CallVoidMethod(sActivity, sHandlePoorPerformance); + CheckJNIException(sEnv, __FUNCTION__); +} } // namespace crow diff --git a/app/src/main/cpp/VRBrowser.h b/app/src/main/cpp/VRBrowser.h index 09e837af5..6e485a9f9 100644 --- a/app/src/main/cpp/VRBrowser.h +++ b/app/src/main/cpp/VRBrowser.h @@ -37,6 +37,7 @@ int32_t GetPointerColor(); bool AreLayersEnabled(); void SetDeviceType(const jint aType); void HaltActivity(const jint aReason); +void HandlePoorPerformance(); } // namespace VRBrowser; } // namespace crow diff --git a/app/src/main/cpp/vrb b/app/src/main/cpp/vrb index 7164170fb..bb4354fa8 160000 --- a/app/src/main/cpp/vrb +++ b/app/src/main/cpp/vrb @@ -1 +1 @@ -Subproject commit 7164170fb86d98b19f913859a18fb128c8749cb6 +Subproject commit bb4354fa8b2cbaae88e7bcc3b2d095341a0138a5 diff --git a/app/src/main/res/layout/options_developer.xml b/app/src/main/res/layout/options_developer.xml index 817ab84a5..bfb434740 100644 --- a/app/src/main/res/layout/options_developer.xml +++ b/app/src/main/res/layout/options_developer.xml @@ -71,6 +71,12 @@ android:layout_height="wrap_content" app:description="@string/developer_options_multiprocess" /> + + settings_console_logs settings_environment_override settings_environment_multiprocess + settings_performance_monitor settings_environment_servo settings_tracking_protection settings_user_agent_version diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 89a90379c..e14e3d6d5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -232,6 +232,12 @@ A dialog should appear with a field labeled with the text, 'Enable Multiprocess'. --> Enable Multiprocess + + Enable Performance Monitor + Enable Servo @@ -699,4 +705,11 @@ %1$s does not have permission to run on this device and will now exit. + + + Unblock Page + + Poor Performance Detected + + The current web page is affecting performance and has been suspended. Reducing the window size can help improve a web page with poor performance.