Commit 38877903 authored by Sergey Ulanov's avatar Sergey Ulanov Committed by Commit Bot

[Fuchsia] Fix crash in CastRunner::OnCameraServiceRequest()

CastRunner::OnComponentDestroyed() wasn't handling the case when
video_capturer_component_ is destroyed. As result
video_capturer_component_ would point to a deleted object. CastRunner
was crashing when trying to use the invalid video_capture_component_ in
OnCameraServiceRequest().

Bug: crbug.com/1122150
Change-Id: I79c8f10cc5964bf9f7ea81e7a026f5276e3d14e9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2377898Reviewed-by: default avatarDavid Dorwin <ddorwin@chromium.org>
Commit-Queue: David Dorwin <ddorwin@chromium.org>
Auto-Submit: Sergey Ulanov <sergeyu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#806056}
parent 38c9ac4a
...@@ -197,6 +197,9 @@ void CastRunner::CancelPendingComponent( ...@@ -197,6 +197,9 @@ void CastRunner::CancelPendingComponent(
void CastRunner::OnComponentDestroyed(CastComponent* component) { void CastRunner::OnComponentDestroyed(CastComponent* component) {
if (component == audio_capturer_component_) if (component == audio_capturer_component_)
audio_capturer_component_ = nullptr; audio_capturer_component_ = nullptr;
if (component == video_capturer_component_)
video_capturer_component_ = nullptr;
} }
fuchsia::web::CreateContextParams CastRunner::GetCommonContextParams() { fuchsia::web::CreateContextParams CastRunner::GetCommonContextParams() {
......
...@@ -38,7 +38,6 @@ ...@@ -38,7 +38,6 @@
#include "fuchsia/base/result_receiver.h" #include "fuchsia/base/result_receiver.h"
#include "fuchsia/base/string_util.h" #include "fuchsia/base/string_util.h"
#include "fuchsia/base/test_devtools_list_fetcher.h" #include "fuchsia/base/test_devtools_list_fetcher.h"
#include "fuchsia/base/test_navigation_listener.h"
#include "fuchsia/base/url_request_rewrite_test_util.h" #include "fuchsia/base/url_request_rewrite_test_util.h"
#include "fuchsia/runners/cast/cast_runner.h" #include "fuchsia/runners/cast/cast_runner.h"
#include "fuchsia/runners/cast/fake_application_config_manager.h" #include "fuchsia/runners/cast/fake_application_config_manager.h"
...@@ -50,6 +49,7 @@ ...@@ -50,6 +49,7 @@
namespace { namespace {
constexpr char kTestAppId[] = "00000000"; constexpr char kTestAppId[] = "00000000";
constexpr char kSecondTestAppId[] = "FFFFFFFF";
constexpr char kBlankAppUrl[] = "/defaultresponse"; constexpr char kBlankAppUrl[] = "/defaultresponse";
constexpr char kEchoHeaderPath[] = "/echoheader?Test"; constexpr char kEchoHeaderPath[] = "/echoheader?Test";
...@@ -267,14 +267,21 @@ class CastRunnerIntegrationTest : public testing::Test { ...@@ -267,14 +267,21 @@ class CastRunnerIntegrationTest : public testing::Test {
std::vector<chromium::cast::ApiBinding> binding_list; std::vector<chromium::cast::ApiBinding> binding_list;
chromium::cast::ApiBinding eval_js_binding; chromium::cast::ApiBinding eval_js_binding;
eval_js_binding.set_before_load_script(cr_fuchsia::MemBufferFromString( eval_js_binding.set_before_load_script(cr_fuchsia::MemBufferFromString(
"function valueOrUndefinedString(value) {"
" return (typeof(value) == 'undefined') ? 'undefined' : value;"
"}"
"window.addEventListener('DOMContentLoaded', (event) => {" "window.addEventListener('DOMContentLoaded', (event) => {"
" var port = cast.__platform__.PortConnector.bind('testport');" " var port = cast.__platform__.PortConnector.bind('testport');"
" port.onmessage = (e) => {" " port.onmessage = (e) => {"
" var result = eval(e.data);" " var result = eval(e.data);"
" if (typeof(result) == \"undefined\") {" " if (result && typeof(result.then) == 'function') {"
" result = \"undefined\";" " result"
" .then(result =>"
" port.postMessage(valueOrUndefinedString(result)))"
" .catch(e => port.postMessage(JSON.stringify(e)));"
" } else {"
" port.postMessage(valueOrUndefinedString(result));"
" }" " }"
" port.postMessage(result);"
" };" " };"
"});", "});",
"test")); "test"));
...@@ -331,8 +338,9 @@ class CastRunnerIntegrationTest : public testing::Test { ...@@ -331,8 +338,9 @@ class CastRunnerIntegrationTest : public testing::Test {
app_config_manager_.AddAppConfig(std::move(app_config)); app_config_manager_.AddAppConfig(std::move(app_config));
} }
void CreateComponentContextAndStartComponent() { void CreateComponentContextAndStartComponent(
auto component_url = base::StringPrintf("cast:%s", kTestAppId); const char* app_id = kTestAppId) {
auto component_url = base::StringPrintf("cast:%s", app_id);
CreateComponentContext(component_url); CreateComponentContext(component_url);
StartCastComponent(component_url); StartCastComponent(component_url);
WaitComponentState(); WaitComponentState();
...@@ -390,8 +398,10 @@ class CastRunnerIntegrationTest : public testing::Test { ...@@ -390,8 +398,10 @@ class CastRunnerIntegrationTest : public testing::Test {
}); });
} }
// Executes |code| in the context of the test application and the returns // Executes |code| in the context of the test application and then returns
// serialized as string. // the result serialized as string. If the code evaluates to a promise then
// execution is blocked until the promise is complete and the result of the
// promise is returned.
std::string ExecuteJavaScript(const std::string& code) { std::string ExecuteJavaScript(const std::string& code) {
fuchsia::web::WebMessage message; fuchsia::web::WebMessage message;
message.set_data(cr_fuchsia::MemBufferFromString(code, "test-msg")); message.set_data(cr_fuchsia::MemBufferFromString(code, "test-msg"));
...@@ -463,9 +473,14 @@ class CastRunnerIntegrationTest : public testing::Test { ...@@ -463,9 +473,14 @@ class CastRunnerIntegrationTest : public testing::Test {
state_loop.Run(); state_loop.Run();
ResetComponentState();
}
void ResetComponentState() {
component_context_ = nullptr; component_context_ = nullptr;
component_services_client_ = nullptr; component_services_client_ = nullptr;
component_state_ = nullptr; component_state_ = nullptr;
test_port_ = nullptr;
} }
base::test::SingleThreadTaskEnvironment task_environment_{ base::test::SingleThreadTaskEnvironment task_environment_{
...@@ -806,28 +821,54 @@ TEST_F(CastRunnerIntegrationTest, CameraRedirect) { ...@@ -806,28 +821,54 @@ TEST_F(CastRunnerIntegrationTest, CameraRedirect) {
auto app_config = auto app_config =
FakeApplicationConfigManager::CreateConfig(kTestAppId, app_url); FakeApplicationConfigManager::CreateConfig(kTestAppId, app_url);
fuchsia::web::PermissionDescriptor canera_permission; fuchsia::web::PermissionDescriptor camera_permission;
canera_permission.set_type(fuchsia::web::PermissionType::CAMERA); camera_permission.set_type(fuchsia::web::PermissionType::CAMERA);
app_config.mutable_permissions()->push_back(std::move(canera_permission)); app_config.mutable_permissions()->push_back(std::move(camera_permission));
app_config_manager_.AddAppConfig(std::move(app_config)); app_config_manager_.AddAppConfig(std::move(app_config));
CreateComponentContextAndStartComponent(); CreateComponentContextAndStartComponent();
// Expect fuchsia.camera3.DeviceWatcher connection to be redirected to the // Expect fuchsia.camera3.DeviceWatcher connection to be redirected to the
// agent. // agent.
base::RunLoop run_loop; bool received_device_watcher_request = false;
component_state_->outgoing_directory()->AddPublicService( component_state_->outgoing_directory()->AddPublicService(
std::make_unique<vfs::Service>( std::make_unique<vfs::Service>(
[quit_closure = run_loop.QuitClosure()]( [&received_device_watcher_request](
zx::channel channel, async_dispatcher_t* dispatcher) mutable { zx::channel channel, async_dispatcher_t* dispatcher) mutable {
std::move(quit_closure).Run(); received_device_watcher_request = true;
}), }),
fuchsia::camera3::DeviceWatcher::Name_); fuchsia::camera3::DeviceWatcher::Name_);
ExecuteJavaScript("connectCamera();"); ExecuteJavaScript("connectCamera();");
EXPECT_TRUE(received_device_watcher_request);
}
// Will quit once camara3::DeviceWatcher is connected. TEST_F(CastRunnerIntegrationTest, CameraAccessAfterComponentShutdown) {
run_loop.Run(); GURL app_url = test_server_.GetURL("/camera.html");
// First app with camera permission.
auto app_config =
FakeApplicationConfigManager::CreateConfig(kTestAppId, app_url);
fuchsia::web::PermissionDescriptor camera_permission;
camera_permission.set_type(fuchsia::web::PermissionType::CAMERA);
app_config.mutable_permissions()->push_back(std::move(camera_permission));
app_config_manager_.AddAppConfig(std::move(app_config));
// Second app without camera permission (but it will still try to access
// fuchsia.camera3.DeviceWatcher service to enumerate devices).
auto app_config_2 =
FakeApplicationConfigManager::CreateConfig(kSecondTestAppId, app_url);
app_config_manager_.AddAppConfig(std::move(app_config_2));
// Start and then shutdown the first app.
CreateComponentContextAndStartComponent(kTestAppId);
ShutdownComponent();
ResetComponentState();
// Start the second app and try to connect the camera. It's expected to fail
// to initialize the camera without crashing CastRunner.
CreateComponentContextAndStartComponent(kSecondTestAppId);
EXPECT_EQ(ExecuteJavaScript("connectCamera();"), "getUserMediaFailed");
} }
class HeadlessCastRunnerIntegrationTest : public CastRunnerIntegrationTest { class HeadlessCastRunnerIntegrationTest : public CastRunnerIntegrationTest {
......
<script> <script>
function connectCamera() { function connectCamera() {
navigator.mediaDevices.getUserMedia({ audio: false, video: true }) return navigator.mediaDevices.getUserMedia({ audio: false, video: true })
.then((stream) => { document.title = 'done'; }); .then((stream) => { return 'getUserMediaSucceeded'; })
.catch((error) => { return 'getUserMediaFailed'; });
} }
</script> </script>
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment