Przemyslaw Pietrzkiewicz | 168bb12 | 2014-11-25 20:15:15 +0100 | [diff] [blame] | 1 | // Copyright 2014 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 | |
James Robinson | b4b7af2 | 2014-12-05 11:21:01 -0800 | [diff] [blame] | 5 | #include "shell/android/android_handler.h" |
Przemyslaw Pietrzkiewicz | 168bb12 | 2014-11-25 20:15:15 +0100 | [diff] [blame] | 6 | |
Benjamin Lerman | 0102229 | 2015-05-13 12:27:35 +0200 | [diff] [blame] | 7 | #include <fcntl.h> |
| 8 | |
Przemyslaw Pietrzkiewicz | 168bb12 | 2014-11-25 20:15:15 +0100 | [diff] [blame] | 9 | #include "base/android/jni_android.h" |
| 10 | #include "base/android/jni_string.h" |
Przemyslaw Pietrzkiewicz | 168bb12 | 2014-11-25 20:15:15 +0100 | [diff] [blame] | 11 | #include "base/files/file_path.h" |
| 12 | #include "base/logging.h" |
Benjamin Lerman | 5d429aa | 2015-05-07 16:21:00 +0200 | [diff] [blame] | 13 | #include "base/message_loop/message_loop.h" |
Benjamin Lerman | 0102229 | 2015-05-13 12:27:35 +0200 | [diff] [blame] | 14 | #include "base/rand_util.h" |
Benjamin Lerman | 5d429aa | 2015-05-07 16:21:00 +0200 | [diff] [blame] | 15 | #include "base/run_loop.h" |
Przemyslaw Pietrzkiewicz | 78ab413 | 2014-12-03 16:49:32 +0100 | [diff] [blame] | 16 | #include "base/scoped_native_library.h" |
Benjamin Lerman | 0102229 | 2015-05-13 12:27:35 +0200 | [diff] [blame] | 17 | #include "base/strings/string_number_conversions.h" |
Benjamin Lerman | 762aa8e | 2015-04-10 13:22:59 +0200 | [diff] [blame] | 18 | #include "base/trace_event/trace_event.h" |
Przemyslaw Pietrzkiewicz | 168bb12 | 2014-11-25 20:15:15 +0100 | [diff] [blame] | 19 | #include "jni/AndroidHandler_jni.h" |
James Robinson | 94ade6b | 2015-08-25 13:02:06 -0700 | [diff] [blame] | 20 | #include "mojo/data_pipe_utils/data_pipe_utils.h" |
Przemyslaw Pietrzkiewicz | 168bb12 | 2014-11-25 20:15:15 +0100 | [diff] [blame] | 21 | #include "mojo/public/c/system/main.h" |
| 22 | #include "mojo/public/cpp/application/application_impl.h" |
Viet-Trung Luu | c1248b2 | 2016-04-26 13:41:55 -0700 | [diff] [blame] | 23 | #include "mojo/public/cpp/application/connect.h" |
James Robinson | b4b7af2 | 2014-12-05 11:21:01 -0800 | [diff] [blame] | 24 | #include "shell/android/run_android_application_function.h" |
Viet-Trung Luu | e126c86 | 2015-03-30 19:20:45 -0700 | [diff] [blame] | 25 | #include "shell/native_application_support.h" |
Przemyslaw Pietrzkiewicz | 168bb12 | 2014-11-25 20:15:15 +0100 | [diff] [blame] | 26 | |
Przemyslaw Pietrzkiewicz | 168bb12 | 2014-11-25 20:15:15 +0100 | [diff] [blame] | 27 | using base::android::AttachCurrentThread; |
| 28 | using base::android::ScopedJavaLocalRef; |
| 29 | using base::android::ConvertJavaStringToUTF8; |
| 30 | using base::android::ConvertUTF8ToJavaString; |
| 31 | using base::android::GetApplicationContext; |
| 32 | |
Viet-Trung Luu | 36faa4d | 2015-03-04 18:08:18 -0800 | [diff] [blame] | 33 | namespace shell { |
Przemyslaw Pietrzkiewicz | 168bb12 | 2014-11-25 20:15:15 +0100 | [diff] [blame] | 34 | |
Przemyslaw Pietrzkiewicz | 78ab413 | 2014-12-03 16:49:32 +0100 | [diff] [blame] | 35 | namespace { |
Viet-Trung Luu | 47e2e35 | 2015-03-04 16:38:18 -0800 | [diff] [blame] | 36 | |
Przemyslaw Pietrzkiewicz | 78ab413 | 2014-12-03 16:49:32 +0100 | [diff] [blame] | 37 | // This function loads the application library, sets the application context and |
| 38 | // thunks and calls into the application MojoMain. To ensure that the thunks are |
| 39 | // set correctly we keep it in the Mojo shell .so and pass the function pointer |
| 40 | // to the helper libbootstrap.so. |
| 41 | void RunAndroidApplication(JNIEnv* env, |
| 42 | jobject j_context, |
Benjamin Lerman | 762aa8e | 2015-04-10 13:22:59 +0200 | [diff] [blame] | 43 | uintptr_t tracing_id, |
Przemyslaw Pietrzkiewicz | 78ab413 | 2014-12-03 16:49:32 +0100 | [diff] [blame] | 44 | const base::FilePath& app_path, |
| 45 | jint j_handle) { |
Viet-Trung Luu | bd07e3a | 2015-04-09 12:43:29 -0700 | [diff] [blame] | 46 | mojo::InterfaceRequest<mojo::Application> application_request = |
Viet-Trung Luu | a531594 | 2016-04-28 11:02:49 -0700 | [diff] [blame] | 47 | mojo::InterfaceRequest<mojo::Application>( |
Viet-Trung Luu | bd07e3a | 2015-04-09 12:43:29 -0700 | [diff] [blame] | 48 | mojo::MakeScopedHandle(mojo::MessagePipeHandle(j_handle))); |
Przemyslaw Pietrzkiewicz | 78ab413 | 2014-12-03 16:49:32 +0100 | [diff] [blame] | 49 | |
| 50 | // Load the library, so that we can set the application context there if |
| 51 | // needed. |
Viet-Trung Luu | e126c86 | 2015-03-30 19:20:45 -0700 | [diff] [blame] | 52 | // TODO(vtl): We'd use a ScopedNativeLibrary, but it doesn't have .get()! |
Benjamin Lerman | 5d429aa | 2015-05-07 16:21:00 +0200 | [diff] [blame] | 53 | base::NativeLibrary app_library = LoadNativeApplication(app_path); |
Viet-Trung Luu | e126c86 | 2015-03-30 19:20:45 -0700 | [diff] [blame] | 54 | if (!app_library) |
Przemyslaw Pietrzkiewicz | 78ab413 | 2014-12-03 16:49:32 +0100 | [diff] [blame] | 55 | return; |
Przemyslaw Pietrzkiewicz | 78ab413 | 2014-12-03 16:49:32 +0100 | [diff] [blame] | 56 | |
| 57 | // Set the application context if needed. Most applications will need to |
| 58 | // access the Android ApplicationContext in which they are run. If the |
| 59 | // application library exports the InitApplicationContext function, we will |
| 60 | // set it there. |
| 61 | const char* init_application_context_name = "InitApplicationContext"; |
| 62 | typedef void (*InitApplicationContextFn)( |
| 63 | const base::android::JavaRef<jobject>&); |
| 64 | InitApplicationContextFn init_application_context = |
| 65 | reinterpret_cast<InitApplicationContextFn>( |
Viet-Trung Luu | e126c86 | 2015-03-30 19:20:45 -0700 | [diff] [blame] | 66 | base::GetFunctionPointerFromNativeLibrary( |
| 67 | app_library, init_application_context_name)); |
Przemyslaw Pietrzkiewicz | 78ab413 | 2014-12-03 16:49:32 +0100 | [diff] [blame] | 68 | if (init_application_context) { |
| 69 | base::android::ScopedJavaLocalRef<jobject> scoped_context(env, j_context); |
| 70 | init_application_context(scoped_context); |
| 71 | } |
| 72 | |
Benjamin Lerman | 762aa8e | 2015-04-10 13:22:59 +0200 | [diff] [blame] | 73 | // The application is ready to be run. |
| 74 | TRACE_EVENT_ASYNC_END0("android_handler", "AndroidHandler::RunApplication", |
| 75 | tracing_id); |
| 76 | |
Przemyslaw Pietrzkiewicz | 78ab413 | 2014-12-03 16:49:32 +0100 | [diff] [blame] | 77 | // Run the application. |
Viet-Trung Luu | e126c86 | 2015-03-30 19:20:45 -0700 | [diff] [blame] | 78 | RunNativeApplication(app_library, application_request.Pass()); |
| 79 | // TODO(vtl): See note about unloading and thread-local destructors above |
| 80 | // declaration of |LoadNativeApplication()|. |
| 81 | base::UnloadNativeLibrary(app_library); |
Przemyslaw Pietrzkiewicz | 78ab413 | 2014-12-03 16:49:32 +0100 | [diff] [blame] | 82 | } |
Viet-Trung Luu | 47e2e35 | 2015-03-04 16:38:18 -0800 | [diff] [blame] | 83 | |
Przemyslaw Pietrzkiewicz | 78ab413 | 2014-12-03 16:49:32 +0100 | [diff] [blame] | 84 | } // namespace |
Przemyslaw Pietrzkiewicz | 168bb12 | 2014-11-25 20:15:15 +0100 | [diff] [blame] | 85 | |
Benjamin Lerman | 6939a5a | 2014-12-16 16:55:42 +0100 | [diff] [blame] | 86 | AndroidHandler::AndroidHandler() : content_handler_factory_(this) { |
| 87 | } |
| 88 | |
| 89 | AndroidHandler::~AndroidHandler() { |
| 90 | } |
| 91 | |
James Robinson | e5ae9e4 | 2015-01-26 17:53:08 -0800 | [diff] [blame] | 92 | void AndroidHandler::RunApplication( |
Viet-Trung Luu | bd07e3a | 2015-04-09 12:43:29 -0700 | [diff] [blame] | 93 | mojo::InterfaceRequest<mojo::Application> application_request, |
| 94 | mojo::URLResponsePtr response) { |
Przemyslaw Pietrzkiewicz | 168bb12 | 2014-11-25 20:15:15 +0100 | [diff] [blame] | 95 | JNIEnv* env = AttachCurrentThread(); |
Benjamin Lerman | 762aa8e | 2015-04-10 13:22:59 +0200 | [diff] [blame] | 96 | uintptr_t tracing_id = reinterpret_cast<uintptr_t>(this); |
| 97 | TRACE_EVENT_ASYNC_BEGIN1("android_handler", "AndroidHandler::RunApplication", |
| 98 | tracing_id, "url", std::string(response->url)); |
Benjamin Lerman | 5d429aa | 2015-05-07 16:21:00 +0200 | [diff] [blame] | 99 | base::FilePath extracted_dir; |
| 100 | base::FilePath cache_dir; |
| 101 | { |
| 102 | base::MessageLoop loop; |
| 103 | handler_task_runner_->PostTask( |
| 104 | FROM_HERE, |
| 105 | base::Bind(&AndroidHandler::ExtractApplication, base::Unretained(this), |
| 106 | base::Unretained(&extracted_dir), |
| 107 | base::Unretained(&cache_dir), base::Passed(response.Pass()), |
| 108 | base::Bind(base::IgnoreResult( |
| 109 | &base::SingleThreadTaskRunner::PostTask), |
| 110 | loop.task_runner(), FROM_HERE, |
| 111 | base::MessageLoop::QuitWhenIdleClosure()))); |
| 112 | base::RunLoop().Run(); |
| 113 | } |
Przemyslaw Pietrzkiewicz | 168bb12 | 2014-11-25 20:15:15 +0100 | [diff] [blame] | 114 | |
Benjamin Lerman | 5d429aa | 2015-05-07 16:21:00 +0200 | [diff] [blame] | 115 | ScopedJavaLocalRef<jstring> j_extracted_dir = |
| 116 | ConvertUTF8ToJavaString(env, extracted_dir.value()); |
| 117 | ScopedJavaLocalRef<jstring> j_cache_dir = |
| 118 | ConvertUTF8ToJavaString(env, cache_dir.value()); |
Przemyslaw Pietrzkiewicz | 78ab413 | 2014-12-03 16:49:32 +0100 | [diff] [blame] | 119 | RunAndroidApplicationFn run_android_application_fn = &RunAndroidApplication; |
| 120 | Java_AndroidHandler_bootstrap( |
Benjamin Lerman | 5d429aa | 2015-05-07 16:21:00 +0200 | [diff] [blame] | 121 | env, GetApplicationContext(), tracing_id, j_extracted_dir.obj(), |
| 122 | j_cache_dir.obj(), |
James Robinson | e5ae9e4 | 2015-01-26 17:53:08 -0800 | [diff] [blame] | 123 | application_request.PassMessagePipe().release().value(), |
Przemyslaw Pietrzkiewicz | 78ab413 | 2014-12-03 16:49:32 +0100 | [diff] [blame] | 124 | reinterpret_cast<jlong>(run_android_application_fn)); |
Przemyslaw Pietrzkiewicz | 168bb12 | 2014-11-25 20:15:15 +0100 | [diff] [blame] | 125 | } |
| 126 | |
Viet-Trung Luu | bd07e3a | 2015-04-09 12:43:29 -0700 | [diff] [blame] | 127 | void AndroidHandler::Initialize(mojo::ApplicationImpl* app) { |
Benjamin Lerman | 5d429aa | 2015-05-07 16:21:00 +0200 | [diff] [blame] | 128 | handler_task_runner_ = base::MessageLoop::current()->task_runner(); |
Viet-Trung Luu | c1248b2 | 2016-04-26 13:41:55 -0700 | [diff] [blame] | 129 | mojo::ConnectToService(app->shell(), "mojo:url_response_disk_cache", |
| 130 | GetProxy(&url_response_disk_cache_)); |
Przemyslaw Pietrzkiewicz | 168bb12 | 2014-11-25 20:15:15 +0100 | [diff] [blame] | 131 | } |
| 132 | |
| 133 | bool AndroidHandler::ConfigureIncomingConnection( |
Viet-Trung Luu | bd07e3a | 2015-04-09 12:43:29 -0700 | [diff] [blame] | 134 | mojo::ApplicationConnection* connection) { |
Przemyslaw Pietrzkiewicz | 168bb12 | 2014-11-25 20:15:15 +0100 | [diff] [blame] | 135 | connection->AddService(&content_handler_factory_); |
| 136 | return true; |
| 137 | } |
| 138 | |
Benjamin Lerman | 5d429aa | 2015-05-07 16:21:00 +0200 | [diff] [blame] | 139 | void AndroidHandler::ExtractApplication(base::FilePath* extracted_dir, |
| 140 | base::FilePath* cache_dir, |
| 141 | mojo::URLResponsePtr response, |
| 142 | const base::Closure& callback) { |
Benjamin Lerman | d15e3f4 | 2015-09-17 11:26:18 +0200 | [diff] [blame] | 143 | url_response_disk_cache_->UpdateAndGetExtracted( |
Benjamin Lerman | 5d429aa | 2015-05-07 16:21:00 +0200 | [diff] [blame] | 144 | response.Pass(), |
| 145 | [extracted_dir, cache_dir, callback](mojo::Array<uint8_t> extracted_path, |
| 146 | mojo::Array<uint8_t> cache_path) { |
| 147 | if (extracted_path.is_null()) { |
| 148 | *extracted_dir = base::FilePath(); |
| 149 | *cache_dir = base::FilePath(); |
| 150 | } else { |
| 151 | *extracted_dir = base::FilePath( |
| 152 | std::string(reinterpret_cast<char*>(&extracted_path.front()), |
| 153 | extracted_path.size())); |
| 154 | *cache_dir = base::FilePath(std::string( |
| 155 | reinterpret_cast<char*>(&cache_path.front()), cache_path.size())); |
| 156 | } |
| 157 | callback.Run(); |
| 158 | }); |
| 159 | } |
| 160 | |
Benjamin Lerman | 0102229 | 2015-05-13 12:27:35 +0200 | [diff] [blame] | 161 | jstring CreateTemporaryFile(JNIEnv* env, |
| 162 | jclass jcaller, |
| 163 | jstring j_directory, |
| 164 | jstring j_basename, |
| 165 | jstring j_extension) { |
| 166 | std::string basename(ConvertJavaStringToUTF8(env, j_basename)); |
| 167 | std::string extension(ConvertJavaStringToUTF8(env, j_extension)); |
| 168 | base::FilePath directory(ConvertJavaStringToUTF8(env, j_directory)); |
| 169 | |
| 170 | for (;;) { |
| 171 | std::string random = base::RandBytesAsString(16); |
| 172 | std::string filename = |
| 173 | basename + base::HexEncode(random.data(), random.size()) + extension; |
| 174 | base::FilePath temporary_file = directory.Append(filename); |
| 175 | int fd = open(temporary_file.value().c_str(), O_CREAT | O_EXCL, 0600); |
| 176 | if (fd != -1) { |
| 177 | close(fd); |
| 178 | return ConvertUTF8ToJavaString(env, temporary_file.value()).Release(); |
| 179 | } |
| 180 | } |
| 181 | } |
| 182 | |
Przemyslaw Pietrzkiewicz | 168bb12 | 2014-11-25 20:15:15 +0100 | [diff] [blame] | 183 | bool RegisterAndroidHandlerJni(JNIEnv* env) { |
| 184 | return RegisterNativesImpl(env); |
| 185 | } |
| 186 | |
Viet-Trung Luu | 36faa4d | 2015-03-04 18:08:18 -0800 | [diff] [blame] | 187 | } // namespace shell |