chromium/content/browser/service_process_host_browsertest.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/342213636): Remove this and spanify to fix the errors.
#pragma allow_unsafe_buffers
#endif

#include "content/public/browser/service_process_host.h"

#include <string.h>

#include "base/memory/shared_memory_mapping.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "base/process/process.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/content_browser_test.h"
#include "services/test/echo/public/mojom/echo.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"

#if BUILDFLAG(IS_WIN)
#include <windows.h>

#include "base/base_paths.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "content/public/browser/service_process_host_passkeys.h"
#endif

namespace content {

#if BUILDFLAG(IS_WIN)
using LoadStatus = echo::mojom::EchoService::LoadStatus;
namespace {
// This is used as the module name to load, and to make the DLL filename.
constexpr const wchar_t* kEchoPreloadLibrary = L"echo_preload_library";

// DLL path relative to current executable.
base::FilePath GetDllPath(std::wstring mod_name) {
  mod_name.append(L".dll");
  auto exe_dir = base::PathService::CheckedGet(base::BasePathKey::DIR_EXE);
  return exe_dir.Append(mod_name);
}
}  // namespace
#endif  // BUILDFLAG(IS_WIN)

constexpr char kTestUrl[] =;

ServiceProcessHostBrowserTest;

class EchoServiceProcessObserver : public ServiceProcessHost::Observer {};

IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, Launch) {}

IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, LocalDisconnectQuits) {}

IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, RemoteDisconnectQuits) {}

IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, AllMessagesReceived) {}

IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, ObserveCrash) {}

IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, IdleTimeout) {}

#if BUILDFLAG(IS_WIN)
IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, PreloadLibraryNotSet) {
  EchoServiceProcessObserver observer;
  auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>(
      ServiceProcessHost::Options().Pass());
  observer.WaitForLaunch();

  base::RunLoop loop;
  echo_service->LoadNativeLibrary(
      GetDllPath(kEchoPreloadLibrary), /*call_sec32_delayload=*/false,
      base::BindLambdaForTesting([&](LoadStatus status, uint32_t result) {
        EXPECT_EQ(LoadStatus::kFailedLoadLibrary, status);
        EXPECT_EQ(DWORD{ERROR_ACCESS_DENIED}, result);
        loop.Quit();
      }));
  loop.Run();
}

IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, PreloadLibraryPreloaded) {
  std::vector<base::FilePath> preloads;
  preloads.push_back(GetDllPath(kEchoPreloadLibrary));

  EchoServiceProcessObserver observer;
  auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>(
      ServiceProcessHost::Options()
          .WithPreloadedLibraries(
              preloads, ServiceProcessHostPreloadLibraries::GetPassKey())
          .Pass());
  observer.WaitForLaunch();

  base::RunLoop loop;
  echo_service->LoadNativeLibrary(
      GetDllPath(kEchoPreloadLibrary),
      /*call_sec32_delayload=*/true,
      base::BindLambdaForTesting([&](LoadStatus status, uint32_t result) {
        EXPECT_EQ(LoadStatus::kSuccess, status);
        EXPECT_EQ(0u, result);
        loop.Quit();
      }));
  loop.Run();
}

IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, PreloadLibraryMultiple) {
  std::vector<base::FilePath> preloads;
  // dbghelp is a placeholder - it will likely be loaded already - this test is
  // validating that multiple libraries can be sent into the child.
  preloads.push_back(GetDllPath(L"dbghelp"));
  preloads.push_back(GetDllPath(kEchoPreloadLibrary));

  EchoServiceProcessObserver observer;
  auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>(
      ServiceProcessHost::Options()
          .WithPreloadedLibraries(
              preloads, ServiceProcessHostPreloadLibraries::GetPassKey())
          .Pass());
  observer.WaitForLaunch();

  base::RunLoop loop;
  echo_service->LoadNativeLibrary(
      GetDllPath(kEchoPreloadLibrary), /*call_sec32_delayload=*/false,
      base::BindLambdaForTesting([&](LoadStatus status, uint32_t result) {
        EXPECT_EQ(LoadStatus::kSuccess, status);
        EXPECT_EQ(0u, result);
        loop.Quit();
      }));
  loop.Run();
}

IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, PreloadLibraryModName) {
  std::vector<base::FilePath> preloads;
  preloads.push_back(GetDllPath(kEchoPreloadLibrary));

  EchoServiceProcessObserver observer;
  auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>(
      ServiceProcessHost::Options()
          .WithPreloadedLibraries(
              preloads, ServiceProcessHostPreloadLibraries::GetPassKey())
          .Pass());
  observer.WaitForLaunch();

  base::RunLoop loop;
  // Once preloaded can people simply provide the module name?
  echo_service->LoadNativeLibrary(
      base::FilePath(kEchoPreloadLibrary), /*call_sec32_delayload=*/false,
      base::BindLambdaForTesting([&](LoadStatus status, uint32_t result) {
        EXPECT_EQ(LoadStatus::kSuccess, status);
        EXPECT_EQ(0u, result);
        loop.Quit();
      }));
  loop.Run();
}

// This test causes a CHECK in the child at startup.
IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, PreloadLibraryBadPath) {
  std::vector<base::FilePath> preloads;
  preloads.push_back(GetDllPath(L"this-is-not-a-library"));

  EchoServiceProcessObserver observer;
  auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>(
      ServiceProcessHost::Options()
          .WithSite(GURL(kTestUrl))  // For WaitForCrash().
          .WithPreloadedLibraries(
              preloads, ServiceProcessHostPreloadLibraries::GetPassKey())
          .Pass());
  observer.WaitForLaunch();
  observer.WaitForCrash();
}
#endif  // BUILDFLAG(IS_WIN)

}  // namespace content