OLD | NEW |
| (Empty) |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "mojo/runner/android/main.h" | |
6 | |
7 #include "base/android/fifo_utils.h" | |
8 #include "base/android/jni_android.h" | |
9 #include "base/android/jni_array.h" | |
10 #include "base/android/jni_string.h" | |
11 #include "base/at_exit.h" | |
12 #include "base/bind.h" | |
13 #include "base/command_line.h" | |
14 #include "base/debug/stack_trace.h" | |
15 #include "base/files/file_path.h" | |
16 #include "base/files/file_util.h" | |
17 #include "base/lazy_instance.h" | |
18 #include "base/logging.h" | |
19 #include "base/macros.h" | |
20 #include "base/message_loop/message_loop.h" | |
21 #include "base/run_loop.h" | |
22 #include "build/build_config.h" | |
23 #include "components/mus/android_loader.h" | |
24 #include "jni/ShellMain_jni.h" | |
25 #include "mojo/message_pump/message_pump_mojo.h" | |
26 #include "mojo/runner/android/android_handler_loader.h" | |
27 #include "mojo/runner/android/background_application_loader.h" | |
28 #include "mojo/runner/android/context_init.h" | |
29 #include "mojo/runner/android/ui_application_loader_android.h" | |
30 #include "mojo/runner/context.h" | |
31 #include "mojo/shell/application_loader.h" | |
32 #include "mojo/shell/runner/host/child_process.h" | |
33 #include "mojo/shell/runner/init.h" | |
34 #include "ui/gl/gl_surface_egl.h" | |
35 | |
36 using base::LazyInstance; | |
37 | |
38 namespace mojo { | |
39 namespace runner { | |
40 | |
41 namespace { | |
42 | |
43 // Command line argument for the communication fifo. | |
44 const char kFifoPath[] = "fifo-path"; | |
45 | |
46 LazyInstance<scoped_ptr<base::MessageLoop>> g_java_message_loop = | |
47 LAZY_INSTANCE_INITIALIZER; | |
48 | |
49 LazyInstance<scoped_ptr<Context>> g_context = LAZY_INSTANCE_INITIALIZER; | |
50 | |
51 LazyInstance<base::android::ScopedJavaGlobalRef<jobject>> g_main_activiy = | |
52 LAZY_INSTANCE_INITIALIZER; | |
53 | |
54 void ConfigureAndroidServices(Context* context) { | |
55 CHECK(context->application_manager()); | |
56 context->application_manager()->SetLoaderForURL( | |
57 make_scoped_ptr( | |
58 new UIApplicationLoader(make_scoped_ptr(new mus::AndroidLoader()), | |
59 g_java_message_loop.Get().get())), | |
60 GURL("mojo:mus")); | |
61 | |
62 // Android handler is bundled with the Mojo shell, because it uses the | |
63 // MojoShell application as the JNI bridge to bootstrap execution of other | |
64 // Android Mojo apps that need JNI. | |
65 context->application_manager()->SetLoaderForURL( | |
66 make_scoped_ptr(new BackgroundApplicationLoader( | |
67 make_scoped_ptr(new AndroidHandlerLoader()), "android_handler", | |
68 base::MessageLoop::TYPE_DEFAULT)), | |
69 GURL("mojo:android_handler")); | |
70 } | |
71 | |
72 void ExitShell() { | |
73 Java_ShellMain_finishActivity(base::android::AttachCurrentThread(), | |
74 g_main_activiy.Get().obj()); | |
75 exit(0); | |
76 } | |
77 | |
78 // Initialize stdout redirection if the command line switch is present. | |
79 void InitializeRedirection() { | |
80 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(kFifoPath)) | |
81 return; | |
82 | |
83 base::FilePath fifo_path = | |
84 base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(kFifoPath); | |
85 base::FilePath directory = fifo_path.DirName(); | |
86 CHECK(base::CreateDirectoryAndGetError(directory, nullptr)) | |
87 << "Unable to create directory: " << directory.value(); | |
88 unlink(fifo_path.value().c_str()); | |
89 CHECK(base::android::CreateFIFO(fifo_path, 0666)) | |
90 << "Unable to create fifo: " << fifo_path.value(); | |
91 CHECK(base::android::RedirectStream(stdout, fifo_path, "w")) | |
92 << "Failed to redirect stdout to file: " << fifo_path.value(); | |
93 CHECK(dup2(STDOUT_FILENO, STDERR_FILENO) != -1) | |
94 << "Unable to redirect stderr to stdout."; | |
95 } | |
96 | |
97 } // namespace | |
98 | |
99 static void Init(JNIEnv* env, | |
100 const JavaParamRef<jclass>& clazz, | |
101 const JavaParamRef<jobject>& activity, | |
102 const JavaParamRef<jstring>& mojo_shell_path, | |
103 const JavaParamRef<jobjectArray>& jparameters, | |
104 const JavaParamRef<jstring>& j_local_apps_directory, | |
105 const JavaParamRef<jstring>& j_tmp_dir) { | |
106 g_main_activiy.Get().Reset(env, activity); | |
107 | |
108 // Setting the TMPDIR environment variable so that applications can use it. | |
109 // TODO(qsr) We will need our subprocesses to inherit this. | |
110 int return_value = | |
111 setenv("TMPDIR", | |
112 base::android::ConvertJavaStringToUTF8(env, j_tmp_dir).c_str(), 1); | |
113 DCHECK_EQ(return_value, 0); | |
114 | |
115 std::vector<std::string> parameters; | |
116 parameters.push_back( | |
117 base::android::ConvertJavaStringToUTF8(env, mojo_shell_path)); | |
118 base::android::AppendJavaStringArrayToStringVector(env, jparameters, | |
119 ¶meters); | |
120 base::CommandLine::Init(0, nullptr); | |
121 base::CommandLine::ForCurrentProcess()->InitFromArgv(parameters); | |
122 | |
123 mojo::shell::InitializeLogging(); | |
124 mojo::shell::WaitForDebuggerIfNecessary(); | |
125 | |
126 InitializeRedirection(); | |
127 | |
128 // We want ~MessageLoop to happen prior to ~Context. Initializing | |
129 // LazyInstances is akin to stack-allocating objects; their destructors | |
130 // will be invoked first-in-last-out. | |
131 base::FilePath shell_file_root( | |
132 base::android::ConvertJavaStringToUTF8(env, j_local_apps_directory)); | |
133 Context* shell_context = new Context; | |
134 g_context.Get().reset(shell_context); | |
135 | |
136 g_java_message_loop.Get().reset(new base::MessageLoopForUI); | |
137 base::MessageLoopForUI::current()->Start(); | |
138 | |
139 shell_context->Init(shell_file_root); | |
140 ConfigureAndroidServices(shell_context); | |
141 | |
142 // This is done after the main message loop is started since it may post | |
143 // tasks. This is consistent with the ordering from the desktop version of | |
144 // this file (../desktop/launcher_process.cc). | |
145 InitContext(shell_context); | |
146 | |
147 // TODO(abarth): At which point should we switch to cross-platform | |
148 // initialization? | |
149 | |
150 gfx::GLSurface::InitializeOneOff(); | |
151 } | |
152 | |
153 static void Start(JNIEnv* env, const JavaParamRef<jclass>& clazz) { | |
154 #if defined(MOJO_SHELL_DEBUG_URL) | |
155 base::CommandLine::ForCurrentProcess()->AppendArg(MOJO_SHELL_DEBUG_URL); | |
156 // Sleep for 5 seconds to give the debugger a chance to attach. | |
157 sleep(5); | |
158 #endif | |
159 | |
160 Context* context = g_context.Pointer()->get(); | |
161 context->RunCommandLineApplication(base::Bind(ExitShell)); | |
162 } | |
163 | |
164 static void AddApplicationURL(JNIEnv* env, | |
165 const JavaParamRef<jclass>& clazz, | |
166 const JavaParamRef<jstring>& jurl) { | |
167 base::CommandLine::ForCurrentProcess()->AppendArg( | |
168 base::android::ConvertJavaStringToUTF8(env, jurl)); | |
169 } | |
170 | |
171 bool RegisterShellMain(JNIEnv* env) { | |
172 return RegisterNativesImpl(env); | |
173 } | |
174 | |
175 Context* GetContext() { | |
176 return g_context.Get().get(); | |
177 } | |
178 | |
179 } // namespace runner | |
180 } // namespace mojo | |
181 | |
182 int main(int argc, char** argv) { | |
183 base::AtExitManager at_exit; | |
184 base::CommandLine::Init(argc, argv); | |
185 | |
186 mojo::shell::InitializeLogging(); | |
187 return mojo::shell::ChildProcessMain(); | |
188 } | |
OLD | NEW |