File: child_process_bridge.mm

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (158 lines) | stat: -rw-r--r-- 5,627 bytes parent folder | download | duplicates (5)
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
155
156
157
158
// Copyright 2024 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/app/ios/appex/child_process_bridge.h"

#include <pthread.h>
#include <xpc/xpc.h>

#include "base/apple/bundle_locations.h"
#include "base/apple/mach_port_rendezvous_ios.h"
#include "base/check_op.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/system/sys_info.h"
#include "content/app/ios/appex/child_process_sandbox.h"
#include "gpu/ipc/common/ios/be_layer_hierarchy_transport.h"
#include "sandbox/policy/switches.h"

class GPUProcessTransport;

// Leaked variables for now.
static size_t g_argc = 0;
static const char** g_argv = nullptr;
static pthread_t g_main_thread;
static id<ChildProcessExtension> g_swift_process;
static xpc_connection_t g_connection;
static std::unique_ptr<GPUProcessTransport> g_gpu_transport;

#define IOS_INIT_EXPORT __attribute__((visibility("default")))

// The embedder must implement this.
extern "C" int ChildProcessMain(int argc, const char** argv);

class GPUProcessTransport : public gpu::BELayerHierarchyTransport {
 public:
  GPUProcessTransport() { gpu::BELayerHierarchyTransport::SetInstance(this); }
  ~GPUProcessTransport() override {
    gpu::BELayerHierarchyTransport::SetInstance(nullptr);
  }

  void ForwardBELayerHierarchyToBrowser(
      gpu::SurfaceHandle surface_handle,
      xpc_object_t ipc_representation) override {
    xpc_object_t message = xpc_dictionary_create(nil, nil, 0);
    xpc_dictionary_set_string(message, "message", "layerHandle");
    xpc_dictionary_set_value(message, "layer", ipc_representation);
    xpc_dictionary_set_uint64(message, "handle", surface_handle);
    xpc_connection_send_message(g_connection, message);
  }
};

extern "C" IOS_INIT_EXPORT void GpuProcessInit() {
  g_gpu_transport = std::make_unique<GPUProcessTransport>();
}

extern "C" IOS_INIT_EXPORT void ChildProcessInit(
    id<ChildProcessExtension> process) {
  // Up two levels: chrome.app/Extensions/chrome_content_process.appex
  NSBundle* bundle = [NSBundle bundleWithURL:[[[NSBundle mainBundle].bundleURL
                                               URLByDeletingLastPathComponent]
                                              URLByDeletingLastPathComponent]];
  base::apple::SetOverrideFrameworkBundle(bundle);
  g_swift_process = process;
}

void* RunMain(void* data) {
  ChildProcessMain((int)g_argc, g_argv);
  return nullptr;
}

extern "C" IOS_INIT_EXPORT void ChildProcessHandleNewConnection(
                                 xpc_connection_t connection) {
  xpc_connection_set_event_handler(connection, ^(xpc_object_t msg) {
    xpc_type_t msg_type = xpc_get_type(msg);
    CHECK_EQ(msg_type, XPC_TYPE_DICTIONARY);
    xpc_object_t args_array = xpc_dictionary_get_array(msg, "args");
    g_argc = xpc_array_get_count(args_array);
    g_argv = new const char*[g_argc];
    for (size_t i = 0; i < g_argc; ++i) {
      g_argv[i] = strdup(xpc_array_get_string(args_array, i));
    }

    // Setup stdout/stderr.
    int fd = xpc_dictionary_dup_fd(msg, "stdout");
    if (fd != -1) {
      dup2(fd, STDOUT_FILENO);
      close(fd);
    }
    fd = xpc_dictionary_dup_fd(msg, "stderr");
    if (fd != -1) {
      dup2(fd, STDERR_FILENO);
      close(fd);
    }

    // See child_process_launcher_helper_ios.mm for discussion of this
    // bookmark data.
    size_t tmp_dir_length = 0;
    const void* tmp_dir =
        xpc_dictionary_get_data(msg, "tmp_dir", &tmp_dir_length);
    CHECK(tmp_dir);
    NSData* bookmark_temp_dir = [NSData dataWithBytes:tmp_dir
                                               length:tmp_dir_length];
    BOOL bookmarkIsStale = NO;
    NSError* error = nil;
    NSURL* tmp_dir_url =
        [NSURL URLByResolvingBookmarkData:bookmark_temp_dir
                                  options:NSURLBookmarkResolutionWithoutUI
                            relativeToURL:nil
                      bookmarkDataIsStale:&bookmarkIsStale
                                    error:&error];
    CHECK(tmp_dir_url);
    std::string file_path = base::SysNSStringToUTF8(tmp_dir_url.path) + "/";
    setenv("TMPDIR", file_path.c_str(), 1);

    base::FilePath assigned_path;
    CHECK(base::GetTempDir(&assigned_path));
    CHECK(assigned_path.value() == file_path);

    mach_port_t port = xpc_dictionary_copy_mach_send(msg, "port");
    base::apple::ScopedMachSendRight server_port(port);
    bool res =
        base::MachPortRendezvousClientIOS::Initialize(std::move(server_port));
    CHECK(res) << "MachPortRendezvousClient failed";
    // TODO(dtapuska): For now we create our own main thread, figure out if we
    // can use the ExtensionMain (thread 0) as the main thread but calling
    // CFRunLoopRunInMode seems to crash it so we can't enter a nested event
    // loop with some objects on the stack.
    pthread_create(&g_main_thread, NULL, RunMain, NULL);
  });
  xpc_connection_activate(connection);
  g_connection = connection;
}

namespace content {

void ChildProcessEnterSandbox() {
  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
          sandbox::policy::switches::kNoSandbox)) {
    return;
  }

  base::SysInfo::IsLowEndDevice();

  // Request the local time before entering the sandbox since that causes a
  // crash after the sandbox is entered.
  base::Time::Now().LocalMidnight();

  [g_swift_process applySandbox];
}

}  // namespace content