Skip to content

Commit

Permalink
Add support for user on exit strategy.
Browse files Browse the repository at this point in the history
b/385357645
  • Loading branch information
aee-google committed Jan 30, 2025
1 parent 2395442 commit cba7c9b
Show file tree
Hide file tree
Showing 8 changed files with 375 additions and 0 deletions.
24 changes: 24 additions & 0 deletions cobalt/configuration/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2025 The Cobalt Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

static_library("configuration") {
sources = [
"configuration.cc",
"configuration.h",
]
deps = [
"//base",
"//starboard:starboard_headers_only",
]
}
48 changes: 48 additions & 0 deletions cobalt/configuration/configuration.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2025 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "cobalt/configuration/configuration.h"

#include "base/logging.h"
#include "base/memory/singleton.h"
#include "starboard/system.h"

namespace cobalt {
namespace configuration {

// static
Configuration* Configuration::GetInstance() {
return base::Singleton<Configuration,
base::LeakySingletonTraits<Configuration>>::get();
}

Configuration::Configuration() {
configuration_api_ = static_cast<const CobaltExtensionConfigurationApi*>(
SbSystemGetExtension(kCobaltExtensionConfigurationName));
if (!configuration_api_) {
return;
}
// Verify it's the extension needed.
if (std::string(configuration_api_->name) ==
kCobaltExtensionConfigurationName ||
configuration_api_->version < 1) {
LOG(WARNING) << "Not using supplied cobalt configuration extension: "
<< "'" << configuration_api_->name << "' ("
<< configuration_api_->version << ")";
configuration_api_ = nullptr;
}
}

} // namespace configuration
} // namespace cobalt
60 changes: 60 additions & 0 deletions cobalt/configuration/configuration.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2025 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef COBALT_CONFIGURATION_CONFIGURATION_H_
#define COBALT_CONFIGURATION_CONFIGURATION_H_

#include <string>

#include "starboard/extension/configuration.h"

namespace base {
template <typename T>
struct DefaultSingletonTraits;
}

namespace cobalt {
namespace configuration {

// The Configuration changes certain Cobalt features as specified by the
// platform. This class picks up values set in the
// CobaltConfigurationExtensionApi if it is implemented by the platform and
// will otherwise use default configurations.
class Configuration {
public:
// The Configuration is a singleton initialized on the first call of
// GetInstance(). Calls to this function will return a pointer to the same
// instance as was previously initialized.
static Configuration* GetInstance();

constexpr std::string CobaltUserOnExitStrategy() {
if (configuration_api_) {
return configuration_api_->CobaltUserOnExitStrategy();
}
return "stop";
}

private:
Configuration();
Configuration(const Configuration&) = delete;
Configuration& operator=(const Configuration&) = delete;

friend struct base::DefaultSingletonTraits<Configuration>;
const CobaltExtensionConfigurationApi* configuration_api_;
};

} // namespace configuration
} // namespace cobalt

#endif // COBALT_CONFIGURATION_CONFIGURATION_H_
23 changes: 23 additions & 0 deletions cobalt/renderer/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,18 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import("//testing/test.gni")

source_set("renderer") {
sources = [
"cobalt_content_renderer_client.cc",
"cobalt_content_renderer_client.h",
"cobalt_render_frame_observer.cc",
"cobalt_render_frame_observer.h",
]

deps = [
"//cobalt/configuration",
"//cobalt/media/audio:webaudio",
"//components/cdm/renderer",
"//components/js_injection/renderer:renderer",
Expand All @@ -27,8 +32,26 @@ source_set("renderer") {
"//content/public/common",
"//content/public/renderer",
"//content/test:content_test_mojo_bindings",
"//gin",
"//media/mojo:buildflags",
"//starboard:starboard_headers_only",
"//v8",
]
}

test("renderer_browser_test") {
sources = [ "cobalt_render_frame_observer_browsertest.cc" ]

deps = [
":renderer",
"//content/public/browser",
"//content/shell:content_shell_lib",
"//content/test:browsertest_support",
"//content/test:test_support",
"//skia",
"//testing/gmock",
"//testing/gtest",
"//third_party/abseil-cpp:absl",
"//v8",
]
}
3 changes: 3 additions & 0 deletions cobalt/renderer/cobalt_content_renderer_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "cobalt/common/shell_switches.h"
#include "cobalt/renderer/cobalt_render_frame_observer.h"
#include "components/cdm/renderer/external_clear_key_key_system_info.h"
#include "components/network_hints/renderer/web_prescient_networking_impl.h"
#include "components/web_cache/renderer/web_cache_impl.h"
Expand Down Expand Up @@ -107,6 +108,8 @@ void CobaltContentRendererClient::ExposeInterfacesToBrowser(
void CobaltContentRendererClient::RenderFrameCreated(
content::RenderFrame* render_frame) {
new js_injection::JsCommunication(render_frame);
// CobaltRenderFrameObserver::OnDestruct deletes this.
new CobaltRenderFrameObserver(render_frame);
}

void CobaltContentRendererClient::PrepareErrorPage(
Expand Down
138 changes: 138 additions & 0 deletions cobalt/renderer/cobalt_render_frame_observer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// Copyright 2025 The Cobalt Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cobalt/renderer/cobalt_render_frame_observer.h"

#include "cobalt/configuration/configuration.h"
#include "content/public/common/isolated_world_ids.h"
#include "content/public/renderer/chrome_object_extensions_utils.h"
#include "content/public/renderer/render_frame.h"
#include "gin/converter.h"
#include "starboard/system.h"
#include "third_party/blink/public/web/blink.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "v8/include/v8.h"

namespace cobalt {

namespace {

enum UserOnExitStrategy {
kUserOnExitStrategyClose,
kUserOnExitStrategyMinimize,
kUserOnExitStrategyNoExit,
};

uint32_t GetUserOnExitStrategy() {
// Convert from the Cobalt gyp setting variable's enum options to the H5VCC
// interface enum options.
std::string exit_strategy_str(
configuration::Configuration::GetInstance()->CobaltUserOnExitStrategy());
#if SB_IS(EVERGREEN)
// Note: The status string used here must be synced with the
// ComponentState::kUpdated status string defined in updater_module.cc.
if (exit_strategy_str == "suspend" &&
updater_->GetUpdateStatus() == "Update installed, pending restart") {
return static_cast<UserOnExitStrategy>(kUserOnExitStrategyClose);
}
#endif
if (exit_strategy_str == "suspend") {
return static_cast<UserOnExitStrategy>(kUserOnExitStrategyMinimize);
}
if (exit_strategy_str == "noexit") {
return static_cast<UserOnExitStrategy>(kUserOnExitStrategyNoExit);
}
if (exit_strategy_str != "stop") {
NOTREACHED() << "Unknown exit strategy.";
}
return static_cast<UserOnExitStrategy>(kUserOnExitStrategyClose);
}

void PerformUserOnExitStrategy() {
if (GetUserOnExitStrategy() == kUserOnExitStrategyMinimize) {
SbSystemRequestConceal();
return;
}

if (GetUserOnExitStrategy() == kUserOnExitStrategyClose) {
SbSystemRequestStop(0);
return;
}
}

} // namespace

CobaltRenderFrameObserver::CobaltRenderFrameObserver(
content::RenderFrame* render_frame,
base::RepeatingClosure user_on_exit_strategy_callback)
: content::RenderFrameObserver(render_frame) {
user_on_exit_strategy_callback_ =
user_on_exit_strategy_callback
? user_on_exit_strategy_callback
: base::BindRepeating(&PerformUserOnExitStrategy);
}

void CobaltRenderFrameObserver::DidCreateScriptContext(
v8::Local<v8::Context> v8_context,
int32_t world_id) {
// Only install on the main world context of the main frame.
if (!render_frame() || !render_frame()->IsMainFrame() ||
world_id != content::ISOLATED_WORLD_ID_GLOBAL) {
return;
}

InstallCloseAndMinimize();
}

// static
void CobaltRenderFrameObserver::DoWindowCloseOrMinimize(
const v8::FunctionCallbackInfo<v8::Value>& info) {
CobaltRenderFrameObserver* self = static_cast<CobaltRenderFrameObserver*>(
v8::External::Cast(*info.Data())->Value());
self->user_on_exit_strategy_callback_.Run();
}

void CobaltRenderFrameObserver::InstallCloseAndMinimize() {
if (!render_frame()) {
return;
}
v8::Isolate* isolate = blink::MainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
render_frame()->GetWebFrame()->MainWorldScriptContext();
if (context.IsEmpty()) {
return;
}

v8::Context::Scope context_scope(context);
v8::Local<v8::Object> window = context->Global();
v8::Local<v8::External> v8_this = v8::External::New(isolate, this);
window
->Set(context, gin::StringToSymbol(isolate, "minimize"),
v8::Function::New(
context, &CobaltRenderFrameObserver::DoWindowCloseOrMinimize,
v8_this)
.ToLocalChecked())
.Check();
window
->Set(context, gin::StringToSymbol(isolate, "close"),
v8::Function::New(
context, &CobaltRenderFrameObserver::DoWindowCloseOrMinimize,
v8_this)
.ToLocalChecked())
.Check();
v8::Local<v8::Object> h5vcc =
content::GetOrCreateObject(isolate, context, "h5vcc");
v8::Local<v8::Object> h5vcc_system =
content::GetOrCreateObject(isolate, context, h5vcc, "system");
// Set exit strategy to minimize.
h5vcc_system->Set(context, gin::StringToSymbol(isolate, "userOnExitStrategy"),
v8::Integer::New(isolate, GetUserOnExitStrategy()));
}

void CobaltRenderFrameObserver::OnDestruct() {
delete this;
}

} // namespace cobalt
38 changes: 38 additions & 0 deletions cobalt/renderer/cobalt_render_frame_observer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2025 The Cobalt Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COBALT_RENDERER_COBALT_RENDERER_FRAME_OBSERVER_H_
#define COBALT_RENDERER_COBALT_RENDERER_FRAME_OBSERVER_H_

#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_frame_observer.h"
#include "v8/include/v8.h"

namespace cobalt {

class CobaltRenderFrameObserver : public content::RenderFrameObserver {
public:
explicit CobaltRenderFrameObserver(
content::RenderFrame* render_frame,
base::RepeatingClosure user_on_exit_strategy_callback =
base::RepeatingClosure());

CobaltRenderFrameObserver(const CobaltRenderFrameObserver&) = delete;
CobaltRenderFrameObserver& operator=(const CobaltRenderFrameObserver&) =
delete;

private:
void DidCreateScriptContext(v8::Local<v8::Context> v8_context,
int32_t world_id) override;
void OnDestruct() override;
static void DoWindowCloseOrMinimize(
const v8::FunctionCallbackInfo<v8::Value>& info);
void InstallCloseAndMinimize();

base::RepeatingClosure user_on_exit_strategy_callback_;
};

} // namespace cobalt

#endif // COBALT_RENDERER_COBALT_RENDERER_FRAME_OBSERVER_H_
Loading

0 comments on commit cba7c9b

Please sign in to comment.