summaryrefslogtreecommitdiff
path: root/chromium/content/browser/child_process_launcher_helper_posix.cc
blob: 42e1c9e4cf18dbeaefa2e1069b64f8af27ef9e3e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/child_process_launcher_helper_posix.h"

#include "base/command_line.h"
#include "base/metrics/field_trial.h"
#include "base/posix/global_descriptors.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "content/browser/posix_file_descriptor_info_impl.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_descriptors.h"
#include "content/public/common/content_switches.h"
#include "mojo/edk/embedder/platform_handle.h"
#include "services/catalog/public/cpp/manifest_parsing_util.h"
#include "services/service_manager/embedder/shared_file_util.h"
#include "services/service_manager/embedder/switches.h"

namespace content {
namespace internal {

namespace {

using RequiredFilesByServiceMap =
    std::map<std::string, catalog::RequiredFileMap>;

RequiredFilesByServiceMap& GetRequiredFilesByServiceMap() {
  static auto* required_files_by_service = new RequiredFilesByServiceMap();
  return *required_files_by_service;
}

std::map<std::string, std::string>& GetServiceNameByProcessTypeMap() {
  static auto* service_name_resolver = new std::map<std::string, std::string>(
      {// The service names are defined in the JSON manifests, so we don't have
       // a constant accessible for them.
       // TODO(jcivelli): remove this map once the service name is accessible
       // from the command line crbug.com/687250
       {switches::kGpuProcess, "content_gpu"},
       {switches::kPpapiPluginProcess, "content_plugin"},
       {switches::kRendererProcess, "content_renderer"},
       {switches::kUtilityProcess, "content_utility"},
       {"ppapi-broker", "ppapi_broker"},
       {"nacl-loader", "nacl_loader"},
       {"nacl-loader-nonsfi", "nacl_loader_nonsfi"}});
  return *service_name_resolver;
}

base::PlatformFile OpenFileIfNecessary(const base::FilePath& path,
                                       base::MemoryMappedFile::Region* region) {
  static auto* opened_files = new std::map<
      base::FilePath,
      std::pair<base::PlatformFile, base::MemoryMappedFile::Region>>;

  const auto& iter = opened_files->find(path);
  if (iter != opened_files->end()) {
    *region = iter->second.second;
    return iter->second.first;
  }
  base::File file = OpenFileToShare(path, region);
  if (!file.IsValid()) {
    return base::kInvalidPlatformFile;
  }
  // g_opened_files becomes the owner of the file descriptor.
  base::PlatformFile fd = file.TakePlatformFile();
  (*opened_files)[path] = std::make_pair(fd, *region);
  return fd;
}

}  // namespace

std::unique_ptr<PosixFileDescriptorInfo> CreateDefaultPosixFilesToMap(
    int child_process_id,
    const mojo::edk::PlatformHandle& mojo_client_handle,
    bool include_service_required_files,
    const std::string& process_type,
    base::CommandLine* command_line) {
  std::unique_ptr<PosixFileDescriptorInfo> files_to_register(
      PosixFileDescriptorInfoImpl::Create());

  base::SharedMemoryHandle shm = base::FieldTrialList::GetFieldTrialHandle();
  if (shm.IsValid()) {
    files_to_register->Share(
        kFieldTrialDescriptor,
        base::SharedMemory::GetFdFromSharedMemoryHandle(shm));
  }

  DCHECK(mojo_client_handle.is_valid());
  files_to_register->Share(kMojoIPCChannel, mojo_client_handle.handle);

  // TODO(jcivelli): remove this "if defined" by making
  // GetAdditionalMappedFilesForChildProcess a no op on Mac.
#if !defined(OS_MACOSX)
  GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
      *command_line, child_process_id, files_to_register.get());
#endif

  if (!include_service_required_files)
    return files_to_register;

  // Also include the files specified in the services' manifests.
  auto service_name_iter = GetServiceNameByProcessTypeMap().find(process_type);
  DCHECK(service_name_iter != GetServiceNameByProcessTypeMap().end())
      << "No service found for process type " << process_type;
  const std::string& service_name = service_name_iter->second;
  auto files_iter = GetRequiredFilesByServiceMap().find(service_name);
  if (files_iter != GetRequiredFilesByServiceMap().end()) {
    const catalog::RequiredFileMap& required_files_map = files_iter->second;
    base::GlobalDescriptors::Key key = kContentDynamicDescriptorStart;
    service_manager::SharedFileSwitchValueBuilder file_switch_value_builder;
    for (const auto& key_path_iter : required_files_map) {
      base::MemoryMappedFile::Region region;
      base::PlatformFile file =
          OpenFileIfNecessary(key_path_iter.second, &region);
      if (file == base::kInvalidPlatformFile) {
        DLOG(WARNING) << "Ignoring invalid file "
                      << key_path_iter.second.value();
        continue;
      }
      file_switch_value_builder.AddEntry(key_path_iter.first, key);
      files_to_register->ShareWithRegion(key, file, region);
      key++;
      DCHECK(key < kContentDynamicDescriptorMax);
    }
    command_line->AppendSwitchASCII(service_manager::switches::kSharedFiles,
                                    file_switch_value_builder.switch_value());
  }

  return files_to_register;
}

void SetFilesToShareForServicePosix(const std::string& service_name,
                                    catalog::RequiredFileMap required_files) {
  if (required_files.empty())
    return;

  if (!base::StartsWith(service_name, "content_",
                        base::CompareCase::INSENSITIVE_ASCII)) {
    // Not a content child service, ignore.
    return;
  }

  DCHECK(GetRequiredFilesByServiceMap().count(service_name) == 0);
  GetRequiredFilesByServiceMap()[service_name] = std::move(required_files);
}

void ResetFilesToShareForTestingPosix() {
  GetRequiredFilesByServiceMap().clear();
}

}  // namespace internal
}  // namespace content