summaryrefslogtreecommitdiffstats
path: root/mojo/runner/native_application_support.cc
blob: 059fcc509fd6f31cdaa9d00c941f52e7b9fc91ce (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
// Copyright 2014 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 "mojo/runner/native_application_support.h"

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "mojo/platform_handle/platform_handle_private_thunks.h"
#include "mojo/public/platform/native/gles2_impl_chromium_extension_thunks.h"
#include "mojo/public/platform/native/gles2_impl_thunks.h"
#include "mojo/public/platform/native/gles2_thunks.h"
#include "mojo/public/platform/native/system_thunks.h"

namespace mojo {
namespace runner {

namespace {

template <typename Thunks>
bool SetThunks(Thunks (*make_thunks)(),
               const char* function_name,
               base::NativeLibrary library) {
  typedef size_t (*SetThunksFn)(const Thunks* thunks);
  SetThunksFn set_thunks = reinterpret_cast<SetThunksFn>(
      base::GetFunctionPointerFromNativeLibrary(library, function_name));
  if (!set_thunks)
    return false;
  Thunks thunks = make_thunks();
  size_t expected_size = set_thunks(&thunks);
  if (expected_size > sizeof(Thunks)) {
    LOG(ERROR) << "Invalid app library: expected " << function_name
               << " to return thunks of size: " << expected_size;
    return false;
  }
  return true;
}

}  // namespace

base::NativeLibrary LoadNativeApplication(const base::FilePath& app_path) {
  DVLOG(2) << "Loading Mojo app in process from library: " << app_path.value();

  base::NativeLibraryLoadError error;
  base::NativeLibrary app_library = base::LoadNativeLibrary(app_path, &error);
  LOG_IF(ERROR, !app_library)
      << "Failed to load app library (error: " << error.ToString() << ")";
  return app_library;
}

bool RunNativeApplication(base::NativeLibrary app_library,
                          InterfaceRequest<Application> application_request) {
  // Tolerate |app_library| being null, to make life easier for callers.
  if (!app_library)
    return false;

  if (!SetThunks(&MojoMakeSystemThunks, "MojoSetSystemThunks", app_library)) {
    LOG(ERROR) << "MojoSetSystemThunks not found";
    return false;
  }

  if (SetThunks(&MojoMakeGLES2ControlThunks, "MojoSetGLES2ControlThunks",
                app_library)) {
    // If we have the control thunks, we should also have the GLES2
    // implementation thunks.
    if (!SetThunks(&MojoMakeGLES2ImplThunks, "MojoSetGLES2ImplThunks",
                   app_library)) {
      LOG(ERROR)
          << "MojoSetGLES2ControlThunks found, but not MojoSetGLES2ImplThunks";
      return false;
    }

    // If the application is using GLES2 extension points, register those
    // thunks. Applications may use or not use any of these, so don't warn if
    // they are missing.
    SetThunks(MojoMakeGLES2ImplChromiumExtensionThunks,
              "MojoSetGLES2ImplChromiumExtensionThunks", app_library);
  }
  // Unlike system thunks, we don't warn on a lack of GLES2 thunks because
  // not everything is a visual app.

  // Go shared library support requires us to initialize the runtime before we
  // start running any go code. This is a temporary patch.
  typedef void (*InitGoRuntimeFn)();
  InitGoRuntimeFn init_go_runtime = reinterpret_cast<InitGoRuntimeFn>(
      base::GetFunctionPointerFromNativeLibrary(app_library, "InitGoRuntime"));
  if (init_go_runtime) {
    DVLOG(2) << "InitGoRuntime: Initializing Go Runtime found in app";
    init_go_runtime();
  }

#if !defined(OS_WIN)
  // On Windows, initializing base::CommandLine with null parameters gets the
  // process's command line from the OS. Other platforms need it to be passed
  // in. This needs to be passed in before the app initializes the command line,
  // which is done as soon as it loads.
  typedef void (*InitCommandLineArgs)(int, const char* const*);
  InitCommandLineArgs init_command_line_args =
      reinterpret_cast<InitCommandLineArgs>(
          base::GetFunctionPointerFromNativeLibrary(app_library,
                                                    "InitCommandLineArgs"));
  if (init_command_line_args) {
    int argc = 0;
    base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
    const char** argv = new const char* [cmd_line->argv().size()];
    for (auto& arg : cmd_line->argv())
      argv[argc++] = arg.c_str();
    init_command_line_args(argc, argv);
  }
#endif

  // Apps need not include platform handle thunks.
  SetThunks(&MojoMakePlatformHandlePrivateThunks,
            "MojoSetPlatformHandlePrivateThunks", app_library);

  typedef MojoResult (*MojoMainFunction)(MojoHandle);
  MojoMainFunction main_function = reinterpret_cast<MojoMainFunction>(
      base::GetFunctionPointerFromNativeLibrary(app_library, "MojoMain"));
  if (!main_function) {
    LOG(ERROR) << "MojoMain not found";
    return false;
  }
  // |MojoMain()| takes ownership of the service handle.
  MojoHandle handle = application_request.PassMessagePipe().release().value();
  MojoResult result = main_function(handle);
  if (result != MOJO_RESULT_OK) {
    LOG(ERROR) << "MojoMain returned error (result: " << result << ")";
  }
  return true;
}

}  // namespace runner
}  // namespace mojo