Split LoadAndRunNativeApplication() ...

(... to separate LoadNativeApplication() and RunNativeApplication()).

* This is to better support sandboxing in the near future. (Note: All
  the thunks are set in RunNativeApplication(). This should be fine with
  respect to sandboxing. More questionable is the calling of
  InitGoRuntime() (though this is supposedly temporary). We'll worry
  about that if it ever becomes a problem.)
* Also rename the files from dynamic_service_runner.* to
  native_application_support.*.
* Also make a separate native_application_support target. (The inclusion
  of dynamic_service_runner.* in the in_process_native_runner target was
  never really right anyway.
* Remove the (trivial -- just for an enum declaration) dependency of
  native_application_support.* on application_manager. This is so the
  future mojo_shell_child binary won't need to depend on half the world,
  and thus link in dynamic libraries it may not need.

R=jamesr@chromium.org

Review URL: https://codereview.chromium.org/1046013002
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn
index 2dac828..f6a9b1b 100644
--- a/mojo/public/cpp/bindings/BUILD.gn
+++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -9,16 +9,9 @@
     "array.h",
     "binding.h",
     "error_handler.h",
-    "interface_ptr_info.h",
     "interface_ptr.h",
-    "map.h",
-    "message.h",
-    "message_filter.h",
-    "no_interface.h",
-    "strong_binding.h",
-    "string.h",
-    "struct_ptr.h",
-    "type_converter.h",
+    "interface_ptr_info.h",
+    "interface_request.h",
     "lib/array_internal.cc",
     "lib/array_internal.h",
     "lib/array_serialization.h",
@@ -55,6 +48,14 @@
     "lib/validate_params.h",
     "lib/validation_errors.cc",
     "lib/validation_errors.h",
+    "map.h",
+    "message.h",
+    "message_filter.h",
+    "no_interface.h",
+    "string.h",
+    "strong_binding.h",
+    "struct_ptr.h",
+    "type_converter.h",
   ]
 
   deps = [
@@ -71,9 +72,9 @@
   sources = [
     "callback.h",
     "lib/callback_internal.h",
-    "lib/template_util.h",
     "lib/shared_data.h",
     "lib/shared_ptr.h",
+    "lib/template_util.h",
   ]
 
   mojo_sdk_deps = [ "mojo/public/cpp/system" ]
diff --git a/shell/BUILD.gn b/shell/BUILD.gn
index a9f81b1..04ed541 100644
--- a/shell/BUILD.gn
+++ b/shell/BUILD.gn
@@ -115,29 +115,18 @@
 
 source_set("in_process_native_runner") {
   sources = [
-    "dynamic_service_runner.cc",
-    "dynamic_service_runner.h",
     "in_process_native_runner.cc",
     "in_process_native_runner.h",
   ]
 
   public_deps = [
-    "//shell/application_manager:application_manager",
+    ":native_application_support",
+    "//shell/application_manager",
   ]
 
   deps = [
     "//base",
-    "//mojo/gles2",
-    "//mojo/public/cpp/system",
   ]
-
-  # This target has to include the public thunk headers, which generally
-  # shouldn't be included without picking an implementation. We are providing
-  # the implementation but the thunk header target cannot declare that we are
-  # permitted to include it since it's in the public SDK and we are not.
-  # Suppress include checking so we can still check the rest of the targets in
-  # this file.
-  check_includes = false
 }
 
 source_set("lib") {
@@ -175,6 +164,7 @@
     ":external_application_registrar_bindings",
     ":init",
     ":in_process_native_runner",
+    ":native_application_support",
     "//base",
     "//base/third_party/dynamic_annotations",
     "//base:base_static",
@@ -234,6 +224,30 @@
   check_includes = false
 }
 
+source_set("native_application_support") {
+  sources = [
+    "native_application_support.cc",
+    "native_application_support.h",
+  ]
+
+  public_deps = [
+    "//mojo/public/cpp/bindings",
+  ]
+
+  deps = [
+    "//base",
+    "//mojo/gles2",
+  ]
+
+  # This target has to include the public thunk headers, which generally
+  # shouldn't be included without picking an implementation. We are providing
+  # the implementation but the thunk header target cannot declare that we are
+  # permitted to include it since it's in the public SDK and we are not.
+  # Suppress include checking so we can still check the rest of the targets in
+  # this file.
+  check_includes = false
+}
+
 source_set("switches") {
   sources = [
     "switches.cc",
diff --git a/shell/android/android_handler.cc b/shell/android/android_handler.cc
index 88b1cfd..a29759d 100644
--- a/shell/android/android_handler.cc
+++ b/shell/android/android_handler.cc
@@ -14,7 +14,7 @@
 #include "mojo/public/c/system/main.h"
 #include "mojo/public/cpp/application/application_impl.h"
 #include "shell/android/run_android_application_function.h"
-#include "shell/dynamic_service_runner.h"
+#include "shell/native_application_support.h"
 
 using base::android::AttachCurrentThread;
 using base::android::ScopedJavaLocalRef;
@@ -40,14 +40,11 @@
 
   // Load the library, so that we can set the application context there if
   // needed.
-  base::NativeLibraryLoadError error;
-  base::ScopedNativeLibrary app_library(
-      base::LoadNativeLibrary(app_path, &error));
-  if (!app_library.is_valid()) {
-    LOG(ERROR) << "Failed to load app library (error: " << error.ToString()
-               << ")";
+  // TODO(vtl): We'd use a ScopedNativeLibrary, but it doesn't have .get()!
+  base::NativeLibrary app_library =
+      LoadNativeApplication(app_path, NativeApplicationCleanup::DELETE);
+  if (!app_library)
     return;
-  }
 
   // Set the application context if needed. Most applications will need to
   // access the Android ApplicationContext in which they are run. If the
@@ -58,15 +55,18 @@
       const base::android::JavaRef<jobject>&);
   InitApplicationContextFn init_application_context =
       reinterpret_cast<InitApplicationContextFn>(
-          app_library.GetFunctionPointer(init_application_context_name));
+          base::GetFunctionPointerFromNativeLibrary(
+              app_library, init_application_context_name));
   if (init_application_context) {
     base::android::ScopedJavaLocalRef<jobject> scoped_context(env, j_context);
     init_application_context(scoped_context);
   }
 
   // Run the application.
-  base::ScopedNativeLibrary app_library_from_runner(LoadAndRunNativeApplication(
-      app_path, NativeRunner::DeleteAppPath, application_request.Pass()));
+  RunNativeApplication(app_library, application_request.Pass());
+  // TODO(vtl): See note about unloading and thread-local destructors above
+  // declaration of |LoadNativeApplication()|.
+  base::UnloadNativeLibrary(app_library);
 }
 
 }  // namespace
diff --git a/shell/app_child_process.cc b/shell/app_child_process.cc
index 387aa5f..1e99dc3 100644
--- a/shell/app_child_process.cc
+++ b/shell/app_child_process.cc
@@ -25,7 +25,7 @@
 #include "mojo/edk/embedder/simple_platform_support.h"
 #include "mojo/public/cpp/system/core.h"
 #include "shell/app_child_process.mojom.h"
-#include "shell/dynamic_service_runner.h"
+#include "shell/native_application_support.h"
 
 namespace mojo {
 namespace shell {
@@ -219,8 +219,8 @@
     unblocker_.Unblock(base::Bind(&AppChildControllerImpl::StartAppOnMainThread,
                                   base::FilePath::FromUTF8Unsafe(app_path),
                                   clean_app_path
-                                      ? NativeRunner::DeleteAppPath
-                                      : NativeRunner::DontDeleteAppPath,
+                                      ? NativeApplicationCleanup::DELETE
+                                      : NativeApplicationCleanup::DONT_DELETE,
                                   base::Passed(&application_request)));
   }
 
@@ -243,7 +243,7 @@
 
   static void StartAppOnMainThread(
       const base::FilePath& app_path,
-      NativeRunner::CleanupBehavior cleanup_behavior,
+      NativeApplicationCleanup cleanup,
       InterfaceRequest<Application> application_request) {
     // TODO(vtl): This is copied from in_process_native_runner.cc.
     DVLOG(2) << "Loading/running Mojo app from " << app_path.value()
@@ -251,8 +251,8 @@
 
     // We intentionally don't unload the native library as its lifetime is the
     // same as that of the process.
-    LoadAndRunNativeApplication(app_path, cleanup_behavior,
-                                application_request.Pass());
+    base::NativeLibrary app_library = LoadNativeApplication(app_path, cleanup);
+    RunNativeApplication(app_library, application_request.Pass());
   }
 
   base::ThreadChecker thread_checker_;
diff --git a/shell/application_manager/BUILD.gn b/shell/application_manager/BUILD.gn
index d7119f0..72a90c8 100644
--- a/shell/application_manager/BUILD.gn
+++ b/shell/application_manager/BUILD.gn
@@ -42,6 +42,7 @@
     "//mojo/edk/system",
     "//mojo/environment:chromium",
     "//mojo/services/content_handler/public/interfaces",
+    "//shell:native_application_support",
     "//shell:switches",
   ]
 }
diff --git a/shell/application_manager/application_manager.cc b/shell/application_manager/application_manager.cc
index b8c4182..50d3468 100644
--- a/shell/application_manager/application_manager.cc
+++ b/shell/application_manager/application_manager.cc
@@ -182,22 +182,23 @@
       parameters);
 
   if (resolved_url.SchemeIsFile()) {
-    new LocalFetcher(resolved_url, GetBaseURLAndQuery(resolved_url, nullptr),
-                     base::Bind(callback, NativeRunner::DontDeleteAppPath));
+    new LocalFetcher(
+        resolved_url, GetBaseURLAndQuery(resolved_url, nullptr),
+        base::Bind(callback, NativeApplicationCleanup::DONT_DELETE));
     return;
   }
 
   if (!network_service_)
     ConnectToService(GURL("mojo:network_service"), &network_service_);
 
-  const NativeRunner::CleanupBehavior cleanup_behavior =
+  const NativeApplicationCleanup cleanup =
       base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDontDeleteOnDownload)
-          ? NativeRunner::DontDeleteAppPath
-          : NativeRunner::DeleteAppPath;
+          ? NativeApplicationCleanup::DONT_DELETE
+          : NativeApplicationCleanup::DELETE;
 
   new NetworkFetcher(disable_cache_, resolved_url, network_service_.get(),
-                     base::Bind(callback, cleanup_behavior));
+                     base::Bind(callback, cleanup));
 }
 
 bool ApplicationManager::ConnectToRunningApplication(
@@ -276,7 +277,7 @@
     ServiceProviderPtr exposed_services,
     const base::Closure& on_application_end,
     const std::vector<std::string>& parameters,
-    NativeRunner::CleanupBehavior cleanup_behavior,
+    NativeApplicationCleanup cleanup,
     scoped_ptr<Fetcher> fetcher) {
   if (!fetcher) {
     // Network error. Drop |application_request| to tell requestor.
@@ -344,13 +345,13 @@
       blocking_pool_,
       base::Bind(&ApplicationManager::RunNativeApplication,
                  weak_ptr_factory_.GetWeakPtr(), base::Passed(request.Pass()),
-                 options, cleanup_behavior, base::Passed(fetcher.Pass())));
+                 options, cleanup, base::Passed(fetcher.Pass())));
 }
 
 void ApplicationManager::RunNativeApplication(
     InterfaceRequest<Application> application_request,
     const NativeRunnerFactory::Options& options,
-    NativeRunner::CleanupBehavior cleanup_behavior,
+    NativeApplicationCleanup cleanup,
     scoped_ptr<Fetcher> fetcher,
     const base::FilePath& path,
     bool path_exists) {
@@ -369,7 +370,7 @@
                path.AsUTF8Unsafe());
   NativeRunner* runner = native_runner_factory_->Create(options).release();
   native_runners_.push_back(runner);
-  runner->Start(path, cleanup_behavior, application_request.Pass(),
+  runner->Start(path, cleanup, application_request.Pass(),
                 base::Bind(&ApplicationManager::CleanupRunner,
                            weak_ptr_factory_.GetWeakPtr(), runner));
 }
diff --git a/shell/application_manager/application_manager.h b/shell/application_manager/application_manager.h
index 3bcbc0c..5a72c85 100644
--- a/shell/application_manager/application_manager.h
+++ b/shell/application_manager/application_manager.h
@@ -18,6 +18,7 @@
 #include "shell/application_manager/application_loader.h"
 #include "shell/application_manager/identity.h"
 #include "shell/application_manager/native_runner.h"
+#include "shell/native_application_support.h"
 #include "url/gurl.h"
 
 namespace base {
@@ -182,12 +183,12 @@
                            ServiceProviderPtr exposed_services,
                            const base::Closure& on_application_end,
                            const std::vector<std::string>& parameters,
-                           NativeRunner::CleanupBehavior cleanup_behavior,
+                           NativeApplicationCleanup cleanup,
                            scoped_ptr<Fetcher> fetcher);
 
   void RunNativeApplication(InterfaceRequest<Application> application_request,
                             const NativeRunnerFactory::Options& options,
-                            NativeRunner::CleanupBehavior cleanup_behavior,
+                            NativeApplicationCleanup cleanup,
                             scoped_ptr<Fetcher> fetcher,
                             const base::FilePath& file_path,
                             bool path_exists);
diff --git a/shell/application_manager/native_runner.h b/shell/application_manager/native_runner.h
index b9b0304..abcff90 100644
--- a/shell/application_manager/native_runner.h
+++ b/shell/application_manager/native_runner.h
@@ -9,6 +9,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "mojo/public/interfaces/application/application.mojom.h"
+#include "shell/native_application_support.h"
 
 namespace base {
 class FilePath;
@@ -21,20 +22,17 @@
 // NativeRunnerFactory to run native applications.
 class NativeRunner {
  public:
-  // Parameter for |Start()| to specify its cleanup behavior.
-  enum CleanupBehavior { DeleteAppPath, DontDeleteAppPath };
-
   virtual ~NativeRunner() {}
 
   // Loads the app in the file at |app_path| and runs it on some other
-  // thread/process. If |cleanup_behavior| is |true|, takes ownership of the
-  // file. |app_completed_callback| is posted (to the thread on which |Start()|
-  // was called) after |MojoMain()| completes.
-  // TODO(vtl): |app_path| and |cleanup_behavior| should probably be moved to
-  // the factory's Create(). Rationale: The factory may need information from
-  // the file to decide what kind of NativeRunner to make.
+  // thread/process. If |cleanup| is |DELETE|, this takes ownership of the file.
+  // |app_completed_callback| is posted (to the thread on which |Start()| was
+  // called) after |MojoMain()| completes.
+  // TODO(vtl): |app_path| and |cleanup| should probably be moved to the
+  // factory's Create(). Rationale: The factory may need information from the
+  // file to decide what kind of NativeRunner to make.
   virtual void Start(const base::FilePath& app_path,
-                     CleanupBehavior cleanup_behavior,
+                     NativeApplicationCleanup cleanup,
                      InterfaceRequest<Application> application_request,
                      const base::Closure& app_completed_callback) = 0;
 };
diff --git a/shell/dynamic_service_runner.cc b/shell/dynamic_service_runner.cc
deleted file mode 100644
index f910d69..0000000
--- a/shell/dynamic_service_runner.cc
+++ /dev/null
@@ -1,126 +0,0 @@
-// 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 "shell/dynamic_service_runner.h"
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "mojo/public/platform/native/gles2_impl_chromium_miscellaneous_thunks.h"
-#include "mojo/public/platform/native/gles2_impl_chromium_sub_image_thunks.h"
-#include "mojo/public/platform/native/gles2_impl_chromium_sync_point_thunks.h"
-#include "mojo/public/platform/native/gles2_impl_chromium_texture_mailbox_thunks.h"
-#include "mojo/public/platform/native/gles2_impl_occlusion_query_ext_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 shell {
-
-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 LoadAndRunNativeApplication(
-    const base::FilePath& app_path,
-    NativeRunner::CleanupBehavior cleanup_behavior,
-    InterfaceRequest<Application> application_request) {
-  DVLOG(2) << "Loading/running Mojo app in process from library: "
-           << app_path.value();
-  base::NativeLibraryLoadError error;
-  base::NativeLibrary app_library = base::LoadNativeLibrary(app_path, &error);
-  if (cleanup_behavior == NativeRunner::DeleteAppPath)
-    DeleteFile(app_path, false);
-  do {
-    if (!app_library) {
-      LOG(ERROR) << "Failed to load app library (error: " << error.ToString()
-                 << ")";
-      break;
-    }
-    if (!SetThunks(&MojoMakeSystemThunks, "MojoSetSystemThunks", app_library)) {
-      LOG(ERROR) << app_path.value() << " MojoSetSystemThunks not found";
-      break;
-    }
-
-    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) << app_path.value()
-                   << " has MojoSetGLES2ControlThunks, "
-                      "but doesn't have MojoSetGLES2ImplThunks.";
-        break;
-      }
-
-      // 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(MojoMakeGLES2ImplChromiumMiscellaneousThunks,
-                "MojoSetGLES2ImplChromiumMiscellaneousThunks", app_library);
-      SetThunks(MojoMakeGLES2ImplChromiumSubImageThunks,
-                "MojoSetGLES2ImplChromiumSubImageThunks", app_library);
-      SetThunks(MojoMakeGLES2ImplChromiumTextureMailboxThunks,
-                "MojoSetGLES2ImplChromiumTextureMailboxThunks", app_library);
-      SetThunks(MojoMakeGLES2ImplChromiumSyncPointThunks,
-                "MojoSetGLES2ImplChromiumSyncPointThunks", app_library);
-      SetThunks(MojoMakeGLES2ImplOcclusionQueryExtThunks,
-                "MojoSetGLES2ImplOcclusionQueryExtThunks", 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();
-    }
-
-    typedef MojoResult (*MojoMainFunction)(MojoHandle);
-    MojoMainFunction main_function = reinterpret_cast<MojoMainFunction>(
-        base::GetFunctionPointerFromNativeLibrary(app_library, "MojoMain"));
-    if (!main_function) {
-      LOG(ERROR) << app_path.value() << " MojoMain not found";
-      break;
-    }
-    // |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) << app_path.value() << " MojoMain returned error(" << result
-                 << ")";
-    }
-  } while (false);
-
-  return app_library;
-}
-
-}  // namespace shell
-}  // namespace mojo
diff --git a/shell/dynamic_service_runner.h b/shell/dynamic_service_runner.h
deleted file mode 100644
index 941152b..0000000
--- a/shell/dynamic_service_runner.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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.
-
-#ifndef SHELL_DYNAMIC_SERVICE_RUNNER_H_
-#define SHELL_DYNAMIC_SERVICE_RUNNER_H_
-
-#include "base/native_library.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "shell/application_manager/application_manager.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace mojo {
-class Application;
-
-namespace shell {
-
-// Loads the service in the DSO specificed by |app_path| and prepares it for
-// execution. Runs the DSO's exported function MojoMain().
-// The NativeLibrary is returned and ownership transferred to the caller.
-// This is so if it is unloaded at all, this can be done safely after this
-// thread is destroyed and any thread-local destructors have been executed.
-base::NativeLibrary LoadAndRunNativeApplication(
-    const base::FilePath& app_path,
-    NativeRunner::CleanupBehavior cleanup_behavior,
-    InterfaceRequest<Application> application_request);
-
-}  // namespace shell
-}  // namespace mojo
-
-#endif  // SHELL_DYNAMIC_SERVICE_RUNNER_H_
diff --git a/shell/in_process_native_runner.cc b/shell/in_process_native_runner.cc
index c6f6e45..0cb510b 100644
--- a/shell/in_process_native_runner.cc
+++ b/shell/in_process_native_runner.cc
@@ -9,14 +9,13 @@
 #include "base/location.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/threading/platform_thread.h"
-#include "shell/dynamic_service_runner.h"
+#include "shell/native_application_support.h"
 
 namespace mojo {
 namespace shell {
 
 InProcessNativeRunner::InProcessNativeRunner(Context* context)
-    : cleanup_behavior_(NativeRunner::DontDeleteAppPath),
-      app_library_(nullptr) {
+    : cleanup_(NativeApplicationCleanup::DONT_DELETE), app_library_(nullptr) {
 }
 
 InProcessNativeRunner::~InProcessNativeRunner() {
@@ -32,11 +31,11 @@
 
 void InProcessNativeRunner::Start(
     const base::FilePath& app_path,
-    NativeRunner::CleanupBehavior cleanup_behavior,
+    NativeApplicationCleanup cleanup,
     InterfaceRequest<Application> application_request,
     const base::Closure& app_completed_callback) {
   app_path_ = app_path;
-  cleanup_behavior_ = cleanup_behavior;
+  cleanup_ = cleanup;
 
   DCHECK(!application_request_.is_pending());
   application_request_ = application_request.Pass();
@@ -56,8 +55,10 @@
            << app_path_.value()
            << " thread id=" << base::PlatformThread::CurrentId();
 
-  app_library_.Reset(LoadAndRunNativeApplication(app_path_, cleanup_behavior_,
-                                                 application_request_.Pass()));
+  // TODO(vtl): ScopedNativeLibrary doesn't have a .get() method!
+  base::NativeLibrary app_library = LoadNativeApplication(app_path_, cleanup_);
+  app_library_.Reset(app_library);
+  RunNativeApplication(app_library, application_request_.Pass());
   app_completed_callback_runner_.Run();
   app_completed_callback_runner_.Reset();
 }
diff --git a/shell/in_process_native_runner.h b/shell/in_process_native_runner.h
index 952b448..f673734 100644
--- a/shell/in_process_native_runner.h
+++ b/shell/in_process_native_runner.h
@@ -12,6 +12,7 @@
 #include "base/scoped_native_library.h"
 #include "base/threading/simple_thread.h"
 #include "shell/application_manager/native_runner.h"
+#include "shell/native_application_support.h"
 
 namespace mojo {
 namespace shell {
@@ -28,7 +29,7 @@
 
   // |NativeRunner| method:
   void Start(const base::FilePath& app_path,
-             NativeRunner::CleanupBehavior cleanup_behavior,
+             NativeApplicationCleanup cleanup,
              InterfaceRequest<Application> application_request,
              const base::Closure& app_completed_callback) override;
 
@@ -37,7 +38,7 @@
   void Run() override;
 
   base::FilePath app_path_;
-  NativeRunner::CleanupBehavior cleanup_behavior_;
+  NativeApplicationCleanup cleanup_;
   InterfaceRequest<Application> application_request_;
   base::Callback<bool(void)> app_completed_callback_runner_;
 
diff --git a/shell/launcher_main.cc b/shell/launcher_main.cc
index 4a95d53..645481b 100644
--- a/shell/launcher_main.cc
+++ b/shell/launcher_main.cc
@@ -15,10 +15,10 @@
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/edk/embedder/process_delegate.h"
 #include "mojo/edk/embedder/simple_platform_support.h"
-#include "shell/dynamic_service_runner.h"
 #include "shell/external_application_registrar_connection.h"
 #include "shell/in_process_native_runner.h"
 #include "shell/init.h"
+#include "shell/native_application_support.h"
 #include "url/gurl.h"
 
 namespace mojo {
@@ -74,7 +74,7 @@
     DCHECK(application_request_.is_pending());
     InProcessNativeRunner service_runner(nullptr);
     base::RunLoop run_loop;
-    service_runner.Start(app_path_, NativeRunner::DontDeleteAppPath,
+    service_runner.Start(app_path_, NativeApplicationCleanup::DONT_DELETE,
                          application_request_.Pass(), run_loop.QuitClosure());
     run_loop.Run();
   }
diff --git a/shell/native_application_support.cc b/shell/native_application_support.cc
new file mode 100644
index 0000000..2cce52d
--- /dev/null
+++ b/shell/native_application_support.cc
@@ -0,0 +1,124 @@
+// 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 "shell/native_application_support.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "mojo/public/platform/native/gles2_impl_chromium_miscellaneous_thunks.h"
+#include "mojo/public/platform/native/gles2_impl_chromium_sub_image_thunks.h"
+#include "mojo/public/platform/native/gles2_impl_chromium_sync_point_thunks.h"
+#include "mojo/public/platform/native/gles2_impl_chromium_texture_mailbox_thunks.h"
+#include "mojo/public/platform/native/gles2_impl_occlusion_query_ext_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 shell {
+
+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,
+                                          NativeApplicationCleanup cleanup) {
+  DVLOG(2) << "Loading Mojo app in process from library: " << app_path.value();
+
+  base::NativeLibraryLoadError error;
+  base::NativeLibrary app_library = base::LoadNativeLibrary(app_path, &error);
+  if (cleanup == NativeApplicationCleanup::DELETE)
+    DeleteFile(app_path, false);
+  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(MojoMakeGLES2ImplChromiumMiscellaneousThunks,
+              "MojoSetGLES2ImplChromiumMiscellaneousThunks", app_library);
+    SetThunks(MojoMakeGLES2ImplChromiumSubImageThunks,
+              "MojoSetGLES2ImplChromiumSubImageThunks", app_library);
+    SetThunks(MojoMakeGLES2ImplChromiumTextureMailboxThunks,
+              "MojoSetGLES2ImplChromiumTextureMailboxThunks", app_library);
+    SetThunks(MojoMakeGLES2ImplChromiumSyncPointThunks,
+              "MojoSetGLES2ImplChromiumSyncPointThunks", app_library);
+    SetThunks(MojoMakeGLES2ImplOcclusionQueryExtThunks,
+              "MojoSetGLES2ImplOcclusionQueryExtThunks", 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();
+  }
+
+  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 shell
+}  // namespace mojo
diff --git a/shell/native_application_support.h b/shell/native_application_support.h
new file mode 100644
index 0000000..f01e5c3
--- /dev/null
+++ b/shell/native_application_support.h
@@ -0,0 +1,47 @@
+// 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.
+
+#ifndef SHELL_NATIVE_APPLICATION_SUPPORT_H_
+#define SHELL_NATIVE_APPLICATION_SUPPORT_H_
+
+#include "base/native_library.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace mojo {
+
+class Application;
+
+namespace shell {
+
+enum class NativeApplicationCleanup { DELETE, DONT_DELETE };
+
+// Loads the native Mojo application from the DSO specified by |app_path|.
+// Returns the |base::NativeLibrary| for the application on success (or null on
+// failure). If |cleanup| is |DELETE|, it will delete |app_path| (regardless of
+// sucess or failure).
+//
+// Note: The caller may choose to eventually unload the returned DSO. If so,
+// this should be done only after the thread on which |LoadNativeApplication()|
+// and |RunNativeApplication()| were called has terminated, so that any
+// thread-local destructors have been executed.
+base::NativeLibrary LoadNativeApplication(const base::FilePath& app_path,
+                                          NativeApplicationCleanup cleanup);
+
+// Runs the native Mojo application from the DSO that was loaded using
+// |LoadNativeApplication()|; this tolerates |app_library| being null. This
+// should be called on the same thread as |LoadNativeApplication()|. Returns
+// true if |MojoMain()| was called (even if it returns an error), and false
+// otherwise.
+// TODO(vtl): Maybe this should also have a |MojoResult| as an out parameter?
+bool RunNativeApplication(base::NativeLibrary app_library,
+                          InterfaceRequest<Application> application_request);
+
+}  // namespace shell
+}  // namespace mojo
+
+#endif  // SHELL_NATIVE_APPLICATION_SUPPORT_H_
diff --git a/shell/native_runner_unittest.cc b/shell/native_runner_unittest.cc
index 5676405..7cad4b9 100644
--- a/shell/native_runner_unittest.cc
+++ b/shell/native_runner_unittest.cc
@@ -33,7 +33,7 @@
     base::MessageLoop::current()->Quit();
   }
   void Start(const base::FilePath& app_path,
-             NativeRunner::CleanupBehavior cleanup_behavior,
+             NativeApplicationCleanup cleanup,
              InterfaceRequest<Application> application_request,
              const base::Closure& app_completed_callback) override {
     state_->runner_was_started = true;
diff --git a/shell/out_of_process_native_runner.cc b/shell/out_of_process_native_runner.cc
index d8f824a..5fd2117 100644
--- a/shell/out_of_process_native_runner.cc
+++ b/shell/out_of_process_native_runner.cc
@@ -31,7 +31,7 @@
 
 void OutOfProcessNativeRunner::Start(
     const base::FilePath& app_path,
-    NativeRunner::CleanupBehavior cleanup_behavior,
+    NativeApplicationCleanup cleanup,
     InterfaceRequest<Application> application_request,
     const base::Closure& app_completed_callback) {
   app_path_ = app_path;
@@ -44,7 +44,7 @@
 
   // TODO(vtl): |app_path.AsUTF8Unsafe()| is unsafe.
   app_child_process_host_->StartApp(
-      app_path.AsUTF8Unsafe(), cleanup_behavior == DeleteAppPath,
+      app_path.AsUTF8Unsafe(), cleanup == NativeApplicationCleanup::DELETE,
       application_request.Pass(),
       base::Bind(&OutOfProcessNativeRunner::AppCompleted,
                  base::Unretained(this)));
diff --git a/shell/out_of_process_native_runner.h b/shell/out_of_process_native_runner.h
index 397ced5..09764ea 100644
--- a/shell/out_of_process_native_runner.h
+++ b/shell/out_of_process_native_runner.h
@@ -27,7 +27,7 @@
 
   // |NativeRunner| method:
   void Start(const base::FilePath& app_path,
-             NativeRunner::CleanupBehavior cleanup_behavior,
+             NativeApplicationCleanup cleanup,
              InterfaceRequest<Application> application_request,
              const base::Closure& app_completed_callback) override;