summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authormichaelbai@chromium.org <michaelbai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-12 05:00:05 +0000
committermichaelbai@chromium.org <michaelbai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-12 05:00:05 +0000
commit5b6f0699827e3dec55b8676bf7893bdab1a1faaa (patch)
treef44d041a8e35e5e3d6ff0e82f4b768777a4069a8 /content
parentfe655231dca7bbbf0f8ca1299b738c4ef133ee19 (diff)
downloadchromium_src-5b6f0699827e3dec55b8676bf7893bdab1a1faaa.zip
chromium_src-5b6f0699827e3dec55b8676bf7893bdab1a1faaa.tar.gz
chromium_src-5b6f0699827e3dec55b8676bf7893bdab1a1faaa.tar.bz2
Added sandboxed process service.
BUG= TEST= Review URL: https://chromiumcodereview.appspot.com/10546079 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@141618 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r--content/DEPS3
-rw-r--r--content/app/DEPS1
-rw-r--r--content/app/android/content_jni_registrar.cc4
-rw-r--r--content/app/android/sandboxed_process_service.cc101
-rw-r--r--content/app/android/sandboxed_process_service.h15
-rw-r--r--content/browser/DEPS1
-rw-r--r--content/common/android/surface_callback.cc159
-rw-r--r--content/common/android/surface_callback.h59
-rw-r--r--content/common/android/surface_texture_peer.cc33
-rw-r--r--content/common/android/surface_texture_peer.h45
-rw-r--r--content/content.gyp17
-rw-r--r--content/content_app.gypi2
-rw-r--r--content/content_common.gypi15
-rw-r--r--content/content_jni.gypi4
-rw-r--r--content/public/android/java/content.xml4
-rw-r--r--content/public/android/java/org/chromium/content/app/SandboxedProcessService.java227
-rw-r--r--content/public/android/java/org/chromium/content/app/SandboxedProcessService0.java12
-rw-r--r--content/public/android/java/org/chromium/content/app/SandboxedProcessService1.java12
-rw-r--r--content/public/android/java/org/chromium/content/app/SandboxedProcessService2.java12
-rw-r--r--content/public/android/java/org/chromium/content/app/SandboxedProcessService3.java12
-rw-r--r--content/public/android/java/org/chromium/content/app/SandboxedProcessService4.java12
-rw-r--r--content/public/android/java/org/chromium/content/browser/SandboxedProcessConnection.java429
-rw-r--r--content/public/android/java/org/chromium/content/common/ISandboxedProcessCallback.aidl14
-rw-r--r--content/public/android/java/org/chromium/content/common/ISandboxedProcessService.aidl18
-rw-r--r--content/public/android/java/org/chromium/content/common/SurfaceCallback.java29
-rw-r--r--content/public/android/java/org/chromium/content/common/common.aidl10
-rw-r--r--content/public/app/android_library_loader_hooks.h4
-rw-r--r--content/shell/DEPS3
-rw-r--r--content/shell/android/AndroidManifest.xml24
29 files changed, 1273 insertions, 8 deletions
diff --git a/content/DEPS b/content/DEPS
index ce5b503..adba74a 100644
--- a/content/DEPS
+++ b/content/DEPS
@@ -70,4 +70,7 @@ include_rules = [
"-ui/aura_shell",
"+webkit",
+
+ # For generated JNI includes
+ "+jni",
]
diff --git a/content/app/DEPS b/content/app/DEPS
index 7ed77a8..321c9ff 100644
--- a/content/app/DEPS
+++ b/content/app/DEPS
@@ -1,5 +1,4 @@
include_rules = [
"+content",
"+media/base", # For initializing media library.
- "+jni", # For generated JNI includes
]
diff --git a/content/app/android/content_jni_registrar.cc b/content/app/android/content_jni_registrar.cc
index 5f01770..2b8e615 100644
--- a/content/app/android/content_jni_registrar.cc
+++ b/content/app/android/content_jni_registrar.cc
@@ -7,12 +7,14 @@
#include "base/android/jni_android.h"
#include "base/android/jni_registrar.h"
#include "content/app/android/content_main.h"
+#include "content/app/android/sandboxed_process_service.h"
#include "content/browser/android/android_browser_process.h"
#include "content/browser/android/command_line.h"
#include "content/browser/android/device_info.h"
#include "content/browser/android/download_controller.h"
#include "content/browser/android/jni_helper.h"
#include "content/browser/android/trace_event_binding.h"
+#include "content/common/android/surface_callback.h"
namespace content {
namespace android {
@@ -24,6 +26,8 @@ base::android::RegistrationMethod kContentRegisteredMethods[] = {
{ "DeviceInfo", RegisterDeviceInfo },
{ "DownloadController", DownloadController::RegisterDownloadController },
{ "JniHelper", RegisterJniHelper },
+ { "SandboxedProcessService", content::RegisterSandboxedProcessService },
+ { "SurfaceCallback", content::RegisterSurfaceCallback },
{ "TraceEvent", RegisterTraceEvent },
};
diff --git a/content/app/android/sandboxed_process_service.cc b/content/app/android/sandboxed_process_service.cc
new file mode 100644
index 0000000..6954d28
--- /dev/null
+++ b/content/app/android/sandboxed_process_service.cc
@@ -0,0 +1,101 @@
+// Copyright (c) 2012 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 "content/app/android/sandboxed_process_service.h"
+
+#include "base/global_descriptors_posix.h"
+#include "base/logging.h"
+#include "content/common/android/surface_texture_peer.h"
+#if !defined(ANDROID_UPSTREAM_BRINGUP)
+#include "content/common/chrome_descriptors.h"
+#endif
+#include "content/public/app/android_library_loader_hooks.h"
+#include "ipc/ipc_descriptors.h"
+#include "jni/sandboxed_process_service_jni.h"
+
+using base::android::AttachCurrentThread;
+using base::android::CheckException;
+
+namespace {
+
+class SurfaceTexturePeerSandboxedImpl : public content::SurfaceTexturePeer {
+ public:
+ // |service| is the instance of
+ // org.chromium.content.app.SandboxedProcessService.
+ SurfaceTexturePeerSandboxedImpl(jobject service)
+ : service_(service) {
+ }
+
+ virtual ~SurfaceTexturePeerSandboxedImpl() {
+ }
+
+ virtual void EstablishSurfaceTexturePeer(base::ProcessHandle pid,
+ SurfaceTextureTarget type,
+ jobject j_surface_texture,
+ int primary_id,
+ int secondary_id) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_SandboxedProcessService_establishSurfaceTexturePeer(env, service_,
+ pid, type, j_surface_texture, primary_id, secondary_id);
+ CheckException(env);
+ }
+
+ private:
+ // The instance of org.chromium.content.app.SandboxedProcessService.
+ jobject service_;
+
+ DISALLOW_COPY_AND_ASSIGN(SurfaceTexturePeerSandboxedImpl);
+};
+
+// Chrome actually uses the renderer code path for all of its sandboxed
+// processes such as renderers, plugins, etc.
+void InternalInitSandboxedProcess(int ipc_fd,
+ int crash_fd,
+ JNIEnv* env,
+ jclass clazz,
+ jobject context,
+ jobject service) {
+ // Set up the IPC file descriptor mapping.
+ base::GlobalDescriptors::GetInstance()->Set(kPrimaryIPCChannel, ipc_fd);
+#if defined(USE_LINUX_BREAKPAD)
+ if (crash_fd > 0) {
+ base::GlobalDescriptors::GetInstance()->Set(kCrashDumpSignal, crash_fd);
+ }
+#endif
+ content::SurfaceTexturePeer::InitInstance(
+ new SurfaceTexturePeerSandboxedImpl(service));
+
+}
+
+} // namespace <anonymous>
+
+static void InitSandboxedProcess(JNIEnv* env,
+ jclass clazz,
+ jobject context,
+ jobject service,
+ jint ipc_fd,
+ jint crash_fd) {
+ InternalInitSandboxedProcess(static_cast<int>(ipc_fd),
+ static_cast<int>(crash_fd), env, clazz, context, service);
+
+ // sandboxed process can't be reused. There is no need to wait for the browser
+ // to unbind the service. Just exit and done.
+ LOG(INFO) << "SandboxedProcessService: Drop out of SandboxedProcessMain.";
+}
+
+static void ExitSandboxedProcess(JNIEnv* env, jclass clazz) {
+ LOG(INFO) << "SandboxedProcessService: Exiting sandboxed process.";
+ // TODO(tedchoc): These methods should also be in the content namespace to
+ // avoid specifying it in the LibraryLoaderExitHook call.
+ content::LibraryLoaderExitHook();
+ _exit(0);
+}
+
+namespace content {
+
+bool RegisterSandboxedProcessService(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace content
diff --git a/content/app/android/sandboxed_process_service.h b/content/app/android/sandboxed_process_service.h
new file mode 100644
index 0000000..26b511f
--- /dev/null
+++ b/content/app/android/sandboxed_process_service.h
@@ -0,0 +1,15 @@
+// Copyright (c) 2012 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 CONTENT_APP_ANDROID_SANDBOXED_PROCESS_SERVICE_H_
+#define CONTENT_APP_ANDROID_SANDBOXED_PROCESS_SERVICE_H_
+#pragma once
+
+#include <jni.h>
+
+namespace content {
+bool RegisterSandboxedProcessService(JNIEnv* env);
+} // namespace content
+
+#endif // CONTENT_APP_ANDROID_SANDBOXED_PROCESS_SERVICE_H_
diff --git a/content/browser/DEPS b/content/browser/DEPS
index 3ed9ff0..960b9e1 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -2,7 +2,6 @@ include_rules = [
"+content/gpu", # For gpu_info_collector.h and in-process GPU
"+content/port/browser",
"+content/public/browser",
- "+jni", # For generated JNI includes
"+media/audio", # For audio input for speech input feature.
"+media/base/android", # For Android JNI registration.
"+ui/ui_controls", # this should probably move into a DEPS file under test.
diff --git a/content/common/android/surface_callback.cc b/content/common/android/surface_callback.cc
new file mode 100644
index 0000000..de83bbd
--- /dev/null
+++ b/content/common/android/surface_callback.cc
@@ -0,0 +1,159 @@
+// Copyright (c) 2012 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 "content/common/android/surface_callback.h"
+
+#include <android/native_window_jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "ui/gl/android_native_window.h"
+#include "jni/surface_callback_jni.h"
+
+using base::android::AttachCurrentThread;
+using base::android::CheckException;
+using base::android::GetMethodID;
+using base::WaitableEvent;
+using content::SurfaceTexturePeer;
+
+namespace {
+
+struct GlobalState {
+ base::Lock registration_lock;
+ // We hold a reference to a message loop proxy which handles message loop
+ // destruction gracefully, which is important since we post tasks from an
+ // arbitrary binder thread while the main thread might be shutting down.
+ // Also, in single-process mode we have two ChildThread objects for render
+ // and gpu thread, so we need to store the msg loops separately.
+ scoped_refptr<base::MessageLoopProxy> native_window_loop;
+ scoped_refptr<base::MessageLoopProxy> video_surface_loop;
+ content::NativeWindowCallback native_window_callback;
+ content::VideoSurfaceCallback video_surface_callback;
+};
+
+base::LazyInstance<GlobalState>::Leaky g_state = LAZY_INSTANCE_INITIALIZER;
+
+void RunNativeWindowCallback(int32 routing_id,
+ int32 renderer_id,
+ ANativeWindow* native_window,
+ WaitableEvent* completion) {
+ g_state.Pointer()->native_window_callback.Run(
+ routing_id, renderer_id, native_window, completion);
+}
+
+void RunVideoSurfaceCallback(int32 routing_id,
+ int32 renderer_id,
+ jobject surface) {
+ g_state.Pointer()->video_surface_callback.Run(
+ routing_id, renderer_id, surface);
+}
+
+} // namespace <anonymous>
+
+static void SetSurface(JNIEnv* env, jclass clazz,
+ jint type,
+ jobject surface,
+ jint primaryID,
+ jint secondaryID) {
+ SetSurfaceAsync(env, surface,
+ static_cast<SurfaceTexturePeer::SurfaceTextureTarget>(type),
+ primaryID, secondaryID, NULL);
+}
+
+
+namespace content {
+
+void ReleaseSurface(jobject surface) {
+ if (surface == NULL)
+ return;
+
+ JNIEnv* env = AttachCurrentThread();
+ CHECK(env);
+
+ jclass cls = env->FindClass("android/view/Surface");
+ DCHECK(cls);
+
+ jmethodID method = env->GetMethodID(cls, "release", "()V");
+ DCHECK(method);
+
+ env->CallVoidMethod(surface, method);
+ DCHECK(env);
+
+ env->DeleteLocalRef(cls);
+}
+
+void SetSurfaceAsync(JNIEnv* env,
+ jobject jsurface,
+ SurfaceTexturePeer::SurfaceTextureTarget type,
+ int primary_id,
+ int secondary_id,
+ WaitableEvent* completion) {
+ base::AutoLock lock(g_state.Pointer()->registration_lock);
+
+ ANativeWindow* native_window = NULL;
+
+ if (jsurface &&
+ type != SurfaceTexturePeer::SET_VIDEO_SURFACE_TEXTURE) {
+ native_window = ANativeWindow_fromSurface(env, jsurface);
+ ReleaseSurface(jsurface);
+ }
+ GlobalState* const global_state = g_state.Pointer();
+
+ switch (type) {
+ case SurfaceTexturePeer::SET_GPU_SURFACE_TEXTURE: {
+ // This should only be sent as a reaction to the renderer
+ // activating compositing. If the GPU process crashes, we expect this
+ // to be resent after the new thread is initialized.
+ DCHECK(global_state->native_window_loop);
+ global_state->native_window_loop->PostTask(
+ FROM_HERE,
+ base::Bind(&RunNativeWindowCallback,
+ primary_id,
+ static_cast<uint32_t>(secondary_id),
+ native_window,
+ completion));
+ // ANativeWindow_release will be called in SetNativeWindow()
+ break;
+ }
+ case SurfaceTexturePeer::SET_VIDEO_SURFACE_TEXTURE: {
+ jobject surface = env->NewGlobalRef(jsurface);
+ DCHECK(global_state->video_surface_loop);
+ global_state->video_surface_loop->PostTask(
+ FROM_HERE,
+ base::Bind(&RunVideoSurfaceCallback,
+ primary_id,
+ secondary_id,
+ surface));
+ break;
+ }
+ }
+}
+
+void RegisterVideoSurfaceCallback(base::MessageLoopProxy* loop,
+ VideoSurfaceCallback& callback) {
+ GlobalState* const global_state = g_state.Pointer();
+ base::AutoLock lock(global_state->registration_lock);
+ global_state->video_surface_loop = loop;
+ global_state->video_surface_callback = callback;
+}
+
+void RegisterNativeWindowCallback(base::MessageLoopProxy* loop,
+ NativeWindowCallback& callback) {
+ GlobalState* const global_state = g_state.Pointer();
+ base::AutoLock lock(global_state->registration_lock);
+ global_state->native_window_loop = loop;
+ global_state->native_window_callback = callback;
+}
+
+bool RegisterSurfaceCallback(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace content
diff --git a/content/common/android/surface_callback.h b/content/common/android/surface_callback.h
new file mode 100644
index 0000000..c45b751
--- /dev/null
+++ b/content/common/android/surface_callback.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 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 CONTENT_COMMON_ANDROID_SURFACE_CALLBACK_H_
+#define CONTENT_COMMON_ANDROID_SURFACE_CALLBACK_H_
+#pragma once
+
+#include <jni.h>
+
+#include "base/callback.h"
+#include "content/common/android/surface_texture_peer.h"
+
+struct ANativeWindow;
+
+namespace base {
+class MessageLoopProxy;
+class WaitableEvent;
+}
+
+namespace content {
+
+// This file implements support for passing surface handles from Java
+// to the correct thread on the native side. On Android, these surface
+// handles can only be passed across processes through Java IPC (Binder),
+// which means calls from Java come in on arbitrary threads. Hence the
+// static nature and the need for the client to register a callback with
+// the corresponding message loop.
+
+// Asynchronously sets the Surface. This can be called from any thread.
+// The Surface will be set to the proper thread based on the type. The
+// nature of primary_id and secondary_id depend on the type of surface
+// and are used to route the surface to the correct client.
+// This method will call release() on the jsurface object to release
+// all the resources. So after calling this method, the caller should
+// not use the jsurface object again.
+void SetSurfaceAsync(JNIEnv* env,
+ jobject jsurface,
+ SurfaceTexturePeer::SurfaceTextureTarget type,
+ int primary_id,
+ int secondary_id,
+ base::WaitableEvent* completion);
+
+void ReleaseSurface(jobject surface);
+
+typedef base::Callback<void(int, int, ANativeWindow*, base::WaitableEvent*)>
+ NativeWindowCallback;
+void RegisterNativeWindowCallback(base::MessageLoopProxy* loop,
+ NativeWindowCallback& callback);
+
+typedef base::Callback<void(int, int, jobject surface)> VideoSurfaceCallback;
+void RegisterVideoSurfaceCallback(base::MessageLoopProxy* loop,
+ VideoSurfaceCallback& callback);
+
+bool RegisterSurfaceCallback(JNIEnv* env);
+
+} // namespace content
+
+#endif // CONTENT_COMMON_ANDROID_SURFACE_CALLBACK_H_
diff --git a/content/common/android/surface_texture_peer.cc b/content/common/android/surface_texture_peer.cc
new file mode 100644
index 0000000..a6fade4
--- /dev/null
+++ b/content/common/android/surface_texture_peer.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2012 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 "content/common/android/surface_texture_peer.h"
+
+#include "base/logging.h"
+
+namespace content {
+
+namespace {
+SurfaceTexturePeer* g_instance_ = NULL;
+} // namespace
+
+SurfaceTexturePeer::SurfaceTexturePeer() {
+}
+
+SurfaceTexturePeer::~SurfaceTexturePeer() {
+}
+
+// static
+SurfaceTexturePeer* SurfaceTexturePeer::GetInstance() {
+ DCHECK(g_instance_);
+ return g_instance_;
+}
+
+// static
+void SurfaceTexturePeer::InitInstance(SurfaceTexturePeer* instance) {
+ DCHECK(!g_instance_);
+ g_instance_ = instance;
+}
+
+} // namespace content
diff --git a/content/common/android/surface_texture_peer.h b/content/common/android/surface_texture_peer.h
new file mode 100644
index 0000000..0b079f0
--- /dev/null
+++ b/content/common/android/surface_texture_peer.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 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 CONTENT_COMMON_ANDROID_SURFACE_TEXTURE_PEER_H_
+#define CONTENT_COMMON_ANDROID_SURFACE_TEXTURE_PEER_H_
+
+#include <jni.h>
+
+#include "base/process.h"
+
+namespace content {
+
+class SurfaceTexturePeer {
+ public:
+ enum SurfaceTextureTarget {
+ // These are used in java so don't change them unless we can
+ // share an enum from java and remove this enum.
+ SET_GPU_SURFACE_TEXTURE = 0, // Contains gpu surface_texture_ and id
+ SET_VIDEO_SURFACE_TEXTURE = 1, // contains video surface_texture_ and id
+ };
+
+ static SurfaceTexturePeer* GetInstance();
+
+ static void InitInstance(SurfaceTexturePeer* instance);
+
+ // Establish the producer end for the given surface texture in another
+ // process.
+ virtual void EstablishSurfaceTexturePeer(base::ProcessHandle pid,
+ SurfaceTextureTarget type,
+ jobject j_surface_texture,
+ int primary_id,
+ int secondary_id) = 0;
+
+ protected:
+ SurfaceTexturePeer();
+ virtual ~SurfaceTexturePeer();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SurfaceTexturePeer);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_ANDROID_SURFACE_TEXTURE_PEER_H_
diff --git a/content/content.gyp b/content/content.gyp
index 737479f..4667205 100644
--- a/content/content.gyp
+++ b/content/content.gyp
@@ -218,9 +218,24 @@
['OS == "android"', {
'targets': [
{
+ 'target_name': 'common_aidl',
+ 'type': 'none',
+ 'variables': {
+ 'aidl_interface_file': '../content/public/android/java/org/chromium/content/common/common.aidl',
+ },
+ 'sources': [
+ '../content/public/android/java/org/chromium/content/common/ISandboxedProcessCallback.aidl',
+ '../content/public/android/java/org/chromium/content/common/ISandboxedProcessService.aidl',
+ ],
+ 'includes': [ '../build/java_aidl.gypi' ],
+ },
+ {
'target_name': 'content_java',
'type': 'none',
- 'dependencies': ['../base/base.gyp:base_java'],
+ 'dependencies': [
+ '../base/base.gyp:base_java',
+ 'content_common',
+ ],
'variables': {
'package_name': 'content',
'java_in_dir': '../content/public/android/java',
diff --git a/content/content_app.gypi b/content/content_app.gypi
index ef1fa7a..8e80042 100644
--- a/content/content_app.gypi
+++ b/content/content_app.gypi
@@ -18,6 +18,8 @@
'app/android/content_main.cc',
'app/android/content_main.h',
'app/android/library_loader_hooks.cc',
+ 'app/android/sandboxed_process_service.cc',
+ 'app/android/sandboxed_process_service.h',
'app/content_main.cc',
'app/content_main_runner.cc',
'app/startup_helper_win.cc',
diff --git a/content/content_common.gypi b/content/content_common.gypi
index 0503dde..82d323e 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -100,6 +100,10 @@
'common/android/address_parser.h',
'common/android/address_parser_internal.cc',
'common/android/address_parser_internal.h',
+ 'common/android/surface_callback.cc',
+ 'common/android/surface_callback.h',
+ 'common/android/surface_texture_peer.cc',
+ 'common/android/surface_texture_peer.h',
'common/appcache/appcache_backend_proxy.cc',
'common/appcache/appcache_backend_proxy.h',
'common/appcache/appcache_dispatcher.cc',
@@ -346,6 +350,17 @@
'common/sandbox_policy.h',
],
}],
+ ['OS=="android"',{
+ 'link_settings': {
+ 'libraries': [
+ '-landroid', # ANativeWindow
+ ],
+ },
+ 'dependencies': [
+ 'content.gyp:content_jni_headers',
+ 'content.gyp:common_aidl',
+ ],
+ }],
['toolkit_uses_gtk == 1', {
'dependencies': [
'../build/linux/system.gyp:gtk',
diff --git a/content/content_jni.gypi b/content/content_jni.gypi
index d00c838..8bfd149 100644
--- a/content/content_jni.gypi
+++ b/content/content_jni.gypi
@@ -10,6 +10,7 @@
'variables': {
'java_sources': [
'public/android/java/org/chromium/content/app/ContentMain.java',
+ 'public/android/java/org/chromium/content/app/SandboxedProcessService.java',
'public/android/java/org/chromium/content/browser/AndroidBrowserProcess.java',
'public/android/java/org/chromium/content/browser/CommandLine.java',
'public/android/java/org/chromium/content/browser/DeviceInfo.java',
@@ -18,10 +19,12 @@
'public/android/java/org/chromium/content/browser/JNIHelper.java',
'public/android/java/org/chromium/content/browser/LibraryLoader.java',
'public/android/java/org/chromium/content/browser/LocationProvider.java',
+ 'public/android/java/org/chromium/content/common/SurfaceCallback.java',
'public/android/java/org/chromium/content/browser/TraceEvent.java',
],
'jni_headers': [
'<(SHARED_INTERMEDIATE_DIR)/content/jni/content_main_jni.h',
+ '<(SHARED_INTERMEDIATE_DIR)/content/jni/sandboxed_process_service_jni.h',
'<(SHARED_INTERMEDIATE_DIR)/content/jni/android_browser_process_jni.h',
'<(SHARED_INTERMEDIATE_DIR)/content/jni/command_line_jni.h',
'<(SHARED_INTERMEDIATE_DIR)/content/jni/device_info_jni.h',
@@ -30,6 +33,7 @@
'<(SHARED_INTERMEDIATE_DIR)/content/jni/jni_helper_jni.h',
'<(SHARED_INTERMEDIATE_DIR)/content/jni/library_loader_jni.h',
'<(SHARED_INTERMEDIATE_DIR)/content/jni/location_provider_jni.h',
+ '<(SHARED_INTERMEDIATE_DIR)/content/jni/surface_callback_jni.h',
'<(SHARED_INTERMEDIATE_DIR)/content/jni/trace_event_jni.h',
],
},
diff --git a/content/public/android/java/content.xml b/content/public/android/java/content.xml
index 2f6d5b8..d899a17 100644
--- a/content/public/android/java/content.xml
+++ b/content/public/android/java/content.xml
@@ -35,7 +35,9 @@
<mkdir dir="${classes.dir}"/>
<!-- Compile the java code from ${src} into ${classes.dir} -->
- <javac srcdir="${src}" destdir="${classes.dir}" debug="true">
+ <!-- Gyp target should have compiled aidl files into java source files in
+ lib.jar (see content.gyp:common_aidl). -->
+ <javac srcdir="${src}:${out.dir}" destdir="${classes.dir}" debug="true">
<classpath>
<pathelement path="${location.base}/android.jar" />
<pathelement path="${jar.dir}/chromium_base.jar" />
diff --git a/content/public/android/java/org/chromium/content/app/SandboxedProcessService.java b/content/public/android/java/org/chromium/content/app/SandboxedProcessService.java
new file mode 100644
index 0000000..fe052cc
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/app/SandboxedProcessService.java
@@ -0,0 +1,227 @@
+// Copyright (c) 2012 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.
+
+package org.chromium.content.app;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Surface;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.content.app.ContentMain;
+import org.chromium.content.browser.SandboxedProcessConnection;
+import org.chromium.content.common.ISandboxedProcessCallback;
+import org.chromium.content.common.ISandboxedProcessService;
+import org.chromium.content.common.SurfaceCallback;
+
+/**
+ * This is the base class for sandboxed services; the SandboxedProcessService0, 1.. etc
+ * subclasses provide the concrete service entry points, to enable the browser to connect
+ * to more than one distinct process (i.e. one process per service number, up to limit of N).
+ * The embedding application must declare these service instances in the application section
+ * of its AndroidManifest.xml, for example with N entries of the form:-
+ * <service android:name="org.chromium.content.browser.SandboxedProcessServiceX"
+ * android:process=":sandboxed_processX" />
+ * for X in 0...N-1 (where N is {@link SandboxedProcessLauncher#MAX_REGISTERED_SERVICES})
+ */
+public class SandboxedProcessService extends Service {
+ private static final String MAIN_THREAD_NAME = "SandboxedProcessMain";
+ private static final String TAG = "SandboxedProcessService";
+ private ISandboxedProcessCallback mCallback;
+
+ // This is the native "Main" thread for the renderer / utility process.
+ private Thread mSandboxMainThread;
+ // Parameters received via IPC, only accessed while holding the mSandboxMainThread monitor.
+ private String[] mCommandLineParams;
+ private ParcelFileDescriptor mIPCFd;
+ private ParcelFileDescriptor mCrashFd;
+
+ private static Context sContext = null;
+ private boolean mLibraryInitialized = false;
+
+ // Binder object used by clients for this service.
+ private final ISandboxedProcessService.Stub mBinder = new ISandboxedProcessService.Stub() {
+ // NOTE: Implement any ISandboxedProcessService methods here.
+ @Override
+ public int setupConnection(Bundle args, ISandboxedProcessCallback callback) {
+ mCallback = callback;
+ synchronized (mSandboxMainThread) {
+ // Allow the command line to be set via bind() intent or setupConnection, but
+ // the FD can only be transferred here.
+ if (mCommandLineParams == null) {
+ mCommandLineParams = args.getStringArray(
+ SandboxedProcessConnection.EXTRA_COMMAND_LINE);
+ }
+ // We must have received the command line by now
+ assert mCommandLineParams != null;
+ mIPCFd = args.getParcelable(SandboxedProcessConnection.EXTRA_IPC_FD);
+ // mCrashFd may be null if native crash reporting is disabled.
+ if (args.containsKey(SandboxedProcessConnection.EXTRA_CRASH_FD)) {
+ mCrashFd = args.getParcelable(SandboxedProcessConnection.EXTRA_CRASH_FD);
+ }
+ mSandboxMainThread.notifyAll();
+ }
+ return Process.myPid();
+ }
+
+ @Override
+ public void setSurface(int type, Surface surface, int primaryID, int secondaryID) {
+ // This gives up ownership of the Surface.
+ SurfaceCallback.setSurface(type, surface, primaryID, secondaryID);
+ }
+ };
+
+ /* package */ static Context getContext() {
+ return sContext;
+ }
+
+ @Override
+ public void onCreate() {
+ sContext = this;
+ super.onCreate();
+
+ mSandboxMainThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ // TODO(michaelbai): Upstream LibraryLoader.java
+ // if (!LibraryLoader.loadNow()) return;
+ synchronized (mSandboxMainThread) {
+ while (mCommandLineParams == null) {
+ mSandboxMainThread.wait();
+ }
+ }
+ // LibraryLoader.initializeOnMainThread(mCommandLineParams);
+ synchronized (mSandboxMainThread) {
+ mLibraryInitialized = true;
+ mSandboxMainThread.notifyAll();
+ while (mIPCFd == null) {
+ mSandboxMainThread.wait();
+ }
+ }
+ int crashFd = (mCrashFd == null) ? -1 : mCrashFd.detachFd();
+ ContentMain.initApplicationContext(sContext.getApplicationContext());
+ nativeInitSandboxedProcess(sContext.getApplicationContext(),
+ SandboxedProcessService.this, mIPCFd.detachFd(), crashFd);
+ ContentMain.start();
+ nativeExitSandboxedProcess();
+ } catch (InterruptedException e) {
+ Log.w(TAG, MAIN_THREAD_NAME + " startup failed: " + e);
+ }
+ }
+ }, MAIN_THREAD_NAME);
+ mSandboxMainThread.start();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (mCommandLineParams == null) {
+ // This process was destroyed before it even started. Nothing more to do.
+ return;
+ }
+ synchronized (mSandboxMainThread) {
+ try {
+ while (!mLibraryInitialized) {
+ // Avoid a potential race in calling through to native code before the library
+ // has loaded.
+ mSandboxMainThread.wait();
+ }
+ } catch (InterruptedException e) {
+ }
+ }
+
+ // This is not synchronized with the main thread in any way, but this is analogous
+ // to how desktop chrome terminates processes using SIGTERM. The mSandboxMainThread
+ // may run briefly before this is executed, but will eventually get a channel error
+ // and similarly commit suicide via SuicideOnChannelErrorFilter().
+ // TODO(tedbo): Why doesn't the activity manager SIGTERM/SIGKILL this service process?
+ nativeExitSandboxedProcess();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ // We call stopSelf() to request that this service be stopped as soon as the client
+ // unbinds. Otherwise the system may keep it around and available for a reconnect. The
+ // sandboxed processes do not currently support reconnect; they must be initialized from
+ // scratch every time.
+ stopSelf();
+
+ synchronized (mSandboxMainThread) {
+ mCommandLineParams = intent.getStringArrayExtra(
+ SandboxedProcessConnection.EXTRA_COMMAND_LINE);
+ mSandboxMainThread.notifyAll();
+ }
+
+ return mBinder;
+ }
+
+ /**
+ * Called from native code to share a surface texture with another child process.
+ * Through using the callback object the browser is used as a proxy to route the
+ * call to the correct process.
+ *
+ * @param pid Process handle of the sandboxed process to share the SurfaceTexture with.
+ * @param type The type of process that the SurfaceTexture is for.
+ * @param surfaceObject The Surface or SurfaceTexture to share with the other sandboxed process.
+ * @param primaryID Used to route the call to the correct client instance.
+ * @param secondaryID Used to route the call to the correct client instance.
+ */
+ @SuppressWarnings("unused")
+ @CalledByNative
+ private void establishSurfaceTexturePeer(int pid, int type, Object surfaceObject, int primaryID,
+ int secondaryID) {
+ if (mCallback == null) {
+ Log.e(TAG, "No callback interface has been provided.");
+ return;
+ }
+
+ Surface surface = null;
+ boolean needRelease = false;
+ if (surfaceObject instanceof Surface) {
+ surface = (Surface)surfaceObject;
+ } else if (surfaceObject instanceof SurfaceTexture) {
+ surface = new Surface((SurfaceTexture)surfaceObject);
+ needRelease = true;
+ } else {
+ Log.e(TAG, "Not a valid surfaceObject: " + surfaceObject);
+ return;
+ }
+ try {
+ mCallback.establishSurfacePeer(pid, type, surface, primaryID, secondaryID);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to call establishSurfaceTexturePeer: " + e);
+ return;
+ } finally {
+ if (needRelease) {
+ surface.release();
+ }
+ }
+ }
+
+ /**
+ * The main entry point for a sandboxed process. This should be called from a new thread since
+ * it will not return until the sandboxed process exits. See sandboxed_process_service.{h,cc}
+ *
+ * @param applicationContext The Application Context of the current process.
+ * @param service The current SandboxedProcessService object.
+ * @param ipcFd File descriptor to use for ipc.
+ * @param crashFd File descriptor for signaling crashes.
+ */
+ private static native void nativeInitSandboxedProcess(Context applicationContext,
+ SandboxedProcessService service, int ipcFd, int crashFd);
+
+ /**
+ * Force the sandboxed process to exit.
+ */
+ private static native void nativeExitSandboxedProcess();
+}
diff --git a/content/public/android/java/org/chromium/content/app/SandboxedProcessService0.java b/content/public/android/java/org/chromium/content/app/SandboxedProcessService0.java
new file mode 100644
index 0000000..1fcd974
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/app/SandboxedProcessService0.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2012 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.
+
+package org.chromium.content.app;
+
+// This is needed to register multiple SandboxedProcess services so that we can have
+// more than one sandboxed process.
+
+public class SandboxedProcessService0 extends SandboxedProcessService {
+
+}
diff --git a/content/public/android/java/org/chromium/content/app/SandboxedProcessService1.java b/content/public/android/java/org/chromium/content/app/SandboxedProcessService1.java
new file mode 100644
index 0000000..24846a7
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/app/SandboxedProcessService1.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2012 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.
+
+package org.chromium.content.app;
+
+// This is needed to register multiple SandboxedProcess services so that we can have
+// more than one sandboxed process.
+
+public class SandboxedProcessService1 extends SandboxedProcessService {
+
+}
diff --git a/content/public/android/java/org/chromium/content/app/SandboxedProcessService2.java b/content/public/android/java/org/chromium/content/app/SandboxedProcessService2.java
new file mode 100644
index 0000000..f8d1802
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/app/SandboxedProcessService2.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2012 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.
+
+package org.chromium.content.app;
+
+// This is needed to register multiple SandboxedProcess services so that we can have
+// more than one sandboxed process.
+
+public class SandboxedProcessService2 extends SandboxedProcessService {
+
+}
diff --git a/content/public/android/java/org/chromium/content/app/SandboxedProcessService3.java b/content/public/android/java/org/chromium/content/app/SandboxedProcessService3.java
new file mode 100644
index 0000000..f5b8fa5
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/app/SandboxedProcessService3.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2012 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.
+
+package org.chromium.content.app;
+
+// This is needed to register multiple SandboxedProcess services so that we can have
+// more than one sandboxed process.
+
+public class SandboxedProcessService3 extends SandboxedProcessService {
+
+}
diff --git a/content/public/android/java/org/chromium/content/app/SandboxedProcessService4.java b/content/public/android/java/org/chromium/content/app/SandboxedProcessService4.java
new file mode 100644
index 0000000..bec8dea
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/app/SandboxedProcessService4.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2012 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.
+
+package org.chromium.content.app;
+
+// This is needed to register multiple SandboxedProcess services so that we can have
+// more than one sandboxed process.
+
+public class SandboxedProcessService4 extends SandboxedProcessService {
+
+}
diff --git a/content/public/android/java/org/chromium/content/browser/SandboxedProcessConnection.java b/content/public/android/java/org/chromium/content/browser/SandboxedProcessConnection.java
new file mode 100644
index 0000000..acc33ad
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/browser/SandboxedProcessConnection.java
@@ -0,0 +1,429 @@
+// Copyright (c) 2012 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.
+
+package org.chromium.content.browser;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.content.app.SandboxedProcessService;
+import org.chromium.content.browser.CommandLine;
+import org.chromium.content.common.ISandboxedProcessCallback;
+import org.chromium.content.common.ISandboxedProcessService;
+// TODO(michaelbai): Move to org.chromium.content.commnon.
+import org.chromium.content.browser.TraceEvent;
+
+public class SandboxedProcessConnection {
+ interface DeathCallback {
+ void onSandboxedProcessDied(int pid);
+ }
+
+ // Names of items placed in the bind intent or connection bundle.
+ public static final String EXTRA_COMMAND_LINE =
+ "com.google.android.apps.chrome.extra.sandbox_command_line";
+ // Note the FD may only be passed in the connection bundle.
+ public static final String EXTRA_IPC_FD = "com.google.android.apps.chrome.extra.sandbox_ipcFd";
+ public static final String EXTRA_CRASH_FD =
+ "com.google.android.apps.chrome.extra.sandbox_crashFd";
+ public static final String EXTRA_CHROME_PAK_FD =
+ "com.google.android.apps.chrome.extra.sandbox_chromePakFd";
+ public static final String EXTRA_LOCALE_PAK_FD =
+ "com.google.android.apps.chrome.extra.sandbox_localePakFd";
+
+ private final Context mContext;
+ private final int mServiceNumber;
+ private final SandboxedProcessConnection.DeathCallback mDeathCallback;
+
+ // Synchronization: While most internal flow occurs on the UI thread, the public API
+ // (specifically bind and unbind) may be called from any thread, hence all entry point methods
+ // into the class are synchronized on the SandboxedProcessConnection instance to protect access
+ // to these members. But see also the TODO where AsyncBoundServiceConnection is created.
+ private ISandboxedProcessService mService = null;
+ private boolean mServiceConnectComplete = false;
+ private int mPID = 0; // Process ID of the corresponding sandboxed process.
+ private HighPriorityConnection mHighPriorityConnection = null;
+ private int mHighPriorityConnectionCount = 0;
+
+ private static final String TAG = "SandboxedProcessConnection";
+
+ private static class ConnectionParams {
+ final String[] mCommandLine;
+ final int mIpcFd;
+ final int mCrashFd;
+ final int mChromePakFd;
+ final int mLocalePakFd;
+ final ISandboxedProcessCallback mCallback;
+ final Runnable mOnConnectionCallback;
+
+ ConnectionParams(
+ String[] commandLine,
+ int ipcFd,
+ int crashFd,
+ int chromePakFd,
+ int localePakFd,
+ ISandboxedProcessCallback callback,
+ Runnable onConnectionCallback) {
+ mCommandLine = commandLine;
+ mIpcFd = ipcFd;
+ mCrashFd = crashFd;
+ mChromePakFd = chromePakFd;
+ mLocalePakFd = localePakFd;
+ mCallback = callback;
+ mOnConnectionCallback = onConnectionCallback;
+ }
+ };
+
+ // Implement the ServiceConnection as an inner class, so it can stem the service
+ // callbacks when cancelled or unbound.
+ class AsyncBoundServiceConnection extends AsyncTask<Intent, Void, Boolean>
+ implements ServiceConnection {
+ private boolean mIsDestroyed = false;
+ private AtomicBoolean mIsBound = new AtomicBoolean(false);
+
+ // AsyncTask
+ @Override
+ protected Boolean doInBackground(Intent... intents) {
+ boolean isBound = mContext.bindService(intents[0], this, Context.BIND_AUTO_CREATE);
+ mIsBound.set(isBound);
+ return isBound;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean boundOK) {
+ synchronized (SandboxedProcessConnection.this) {
+ if (!boundOK && !mIsDestroyed) {
+ SandboxedProcessConnection.this.onBindFailed();
+ }
+ // else: bind will complete asynchronously with a callback to onServiceConnected().
+ }
+ }
+
+ @Override
+ protected void onCancelled(Boolean boundOK) {
+ // According to {@link AsyncTask#onCancelled(Object)}, the Object can be null.
+ if (boundOK != null && boundOK) {
+ unBindIfAble();
+ }
+ }
+
+ /**
+ * Unbinds this connection if it hasn't already been unbound. There's a guard to check that
+ * we haven't already been unbound because the Browser process cancelling a connection can
+ * race with something else (Android?) cancelling the connection.
+ */
+ private void unBindIfAble() {
+ if (mIsBound.getAndSet(false)) {
+ mContext.unbindService(this);
+ }
+ }
+
+ // ServiceConnection
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (SandboxedProcessConnection.this) {
+ if (!mIsDestroyed) {
+ SandboxedProcessConnection.this.onServiceConnected(name, service);
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ synchronized (SandboxedProcessConnection.this) {
+ if (!mIsDestroyed) {
+ SandboxedProcessConnection.this.onServiceDisconnected(name);
+ }
+ }
+ }
+
+ public void destroy() {
+ assert Thread.holdsLock(SandboxedProcessConnection.this);
+ if (!cancel(false)) {
+ unBindIfAble();
+ }
+ mIsDestroyed = true;
+ }
+ }
+
+ // This is only valid while the connection is being established.
+ private ConnectionParams mConnectionParams;
+ private AsyncBoundServiceConnection mServiceConnection;
+
+ SandboxedProcessConnection(Context context, int number,
+ SandboxedProcessConnection.DeathCallback deathCallback) {
+ mContext = context;
+ mServiceNumber = number;
+ mDeathCallback = deathCallback;
+ }
+
+ int getServiceNumber() {
+ return mServiceNumber;
+ }
+
+ synchronized ISandboxedProcessService getService() {
+ return mService;
+ }
+
+ private Intent createServiceBindIntent() {
+ Intent intent = new Intent();
+ String n = SandboxedProcessService.class.getName();
+ intent.setClassName(mContext, n + mServiceNumber);
+ intent.setPackage(mContext.getPackageName());
+ return intent;
+ }
+
+ /**
+ * Bind to an ISandboxedProcessService. This must be followed by a call to setupConnection()
+ * to setup the connection parameters. (These methods are separated to allow the client
+ * to pass whatever parameters they have available here, and complete the remainder
+ * later while reducing the connection setup latency).
+ *
+ * @param commandLine (Optional) Command line for the sandboxed process. If omitted, then
+ * the command line parameters must instead be passed to setupConnection().
+ */
+ synchronized void bind(String[] commandLine) {
+ TraceEvent.begin();
+ final Intent intent = createServiceBindIntent();
+
+ if (commandLine != null) {
+ intent.putExtra(EXTRA_COMMAND_LINE, commandLine);
+ }
+ // TODO(joth): By the docs, AsyncTasks should only be created on the UI thread, but
+ // bind() currently 'may' be called on any thread. In practice it's only ever called
+ // from UI, but it's not guaranteed. See http://b/5694925.
+ Looper mainLooper = Looper.getMainLooper();
+ if (Looper.myLooper() == mainLooper) {
+ mServiceConnection = new AsyncBoundServiceConnection();
+ // On completion this will call back to onServiceConnected().
+ mServiceConnection.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, intent);
+ } else {
+ // TODO(jcivelli): http://b/5694925 we only have to post to the UI thread because we use
+ // an AsyncTask and it requires it. Replace that AsyncTask by running our own thread and
+ // change this so we run directly from the current thread.
+ new Handler(mainLooper).postAtFrontOfQueue(new Runnable() {
+ public void run() {
+ mServiceConnection = new AsyncBoundServiceConnection();
+ // On completion this will call back to onServiceConnected().
+ mServiceConnection.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
+ intent);
+ }
+ });
+ }
+ TraceEvent.end();
+ }
+
+ /** Setup a connection previous bound via a call to bind().
+ *
+ * This establishes the parameters that were not already supplied in bind.
+ * @param commandLine (Optional) will be ignored if the command line was already sent in bind()
+ * @param ipcFd The file descriptor that will be used by the sandbox process for IPC.
+ * @param crashFd (Optional) file descriptor that will be used for crash dumps.
+ * @param callback Used for status updates regarding this process connection.
+ * @param onConnectionCallback will be run when the connection is setup and ready to use.
+ */
+ synchronized void setupConnection(
+ String[] commandLine,
+ int ipcFd,
+ int crashFd,
+ int chromePakFd,
+ int localePakFd,
+ ISandboxedProcessCallback callback,
+ Runnable onConnectionCallback) {
+ TraceEvent.begin();
+ assert mConnectionParams == null;
+ mConnectionParams = new ConnectionParams(commandLine, ipcFd, crashFd, chromePakFd,
+ localePakFd, callback, onConnectionCallback);
+ if (mServiceConnectComplete) {
+ doConnectionSetup();
+ }
+ TraceEvent.end();
+ }
+
+ /**
+ * Unbind the ISandboxedProcessService. It is safe to call this multiple times.
+ */
+ synchronized void unbind() {
+ if (mServiceConnection != null) {
+ mServiceConnection.destroy();
+ mServiceConnection = null;
+ }
+ if (mService != null) {
+ if (mHighPriorityConnection != null) {
+ unbindHighPriority(true);
+ }
+ mService = null;
+ mPID = 0;
+ }
+ mConnectionParams = null;
+ mServiceConnectComplete = false;
+ }
+
+ // Called on the main thread to notify that the service is connected.
+ private void onServiceConnected(ComponentName className, IBinder service) {
+ assert Thread.holdsLock(this);
+ TraceEvent.begin();
+ mServiceConnectComplete = true;
+ mService = ISandboxedProcessService.Stub.asInterface(service);
+ if (mConnectionParams != null) {
+ doConnectionSetup();
+ }
+ TraceEvent.end();
+ }
+
+ // Called on the main thread to notify that the bindService() call failed (returned false).
+ private void onBindFailed() {
+ assert Thread.holdsLock(this);
+ mServiceConnectComplete = true;
+ if (mConnectionParams != null) {
+ doConnectionSetup();
+ }
+ }
+
+ /**
+ * Called when the connection parameters have been set, and a connection has been established
+ * (as signaled by onServiceConnected), or if the connection failed (mService will be false).
+ */
+ private void doConnectionSetup() {
+ TraceEvent.begin();
+ assert mServiceConnectComplete && mConnectionParams != null;
+ // Capture the callback before it is potentially nulled in unbind().
+ Runnable onConnectionCallback =
+ mConnectionParams != null ? mConnectionParams.mOnConnectionCallback : null;
+ if (onConnectionCallback == null) {
+ unbind();
+ } else if (mService != null) {
+ try {
+ ParcelFileDescriptor ipcFdParcel =
+ ParcelFileDescriptor.fromFd(mConnectionParams.mIpcFd);
+ Bundle bundle = new Bundle();
+ bundle.putStringArray(EXTRA_COMMAND_LINE, mConnectionParams.mCommandLine);
+ bundle.putParcelable(EXTRA_IPC_FD, ipcFdParcel);
+
+ ParcelFileDescriptor chromePakFdParcel =
+ ParcelFileDescriptor.fromFd(mConnectionParams.mChromePakFd);
+ bundle.putParcelable(EXTRA_CHROME_PAK_FD, chromePakFdParcel);
+
+ ParcelFileDescriptor localePakFdParcel =
+ ParcelFileDescriptor.fromFd(mConnectionParams.mLocalePakFd);
+ bundle.putParcelable(EXTRA_LOCALE_PAK_FD, localePakFdParcel);
+
+ try {
+ ParcelFileDescriptor crashFdParcel =
+ ParcelFileDescriptor.fromFd(mConnectionParams.mCrashFd);
+ bundle.putParcelable(EXTRA_CRASH_FD, crashFdParcel);
+ // We will let the GC close the crash ParcelFileDescriptor.
+ } catch (java.io.IOException e) {
+ Log.w(TAG, "Invalid crash Fd. Native crash reporting will be disabled.");
+ }
+
+ mPID = mService.setupConnection(bundle, mConnectionParams.mCallback);
+ ipcFdParcel.close(); // We proactivley close now rather than wait for GC &
+ // finalizer.
+ } catch(java.io.IOException e) {
+ Log.w(TAG, "Invalid ipc FD.");
+ } catch(android.os.RemoteException e) {
+ Log.w(TAG, "Exception when trying to call service method: "
+ + e);
+ }
+ }
+ mConnectionParams = null;
+ if (onConnectionCallback != null) {
+ onConnectionCallback.run();
+ }
+ TraceEvent.end();
+ }
+
+ // Called on the main thread to notify that the sandboxed service did not disconnect gracefully.
+ private void onServiceDisconnected(ComponentName className) {
+ assert Thread.holdsLock(this);
+ int pid = mPID; // Stash pid & connection callback since unbind() will clear them.
+ Runnable onConnectionCallback =
+ mConnectionParams != null ? mConnectionParams.mOnConnectionCallback : null;
+ Log.w(TAG, "onServiceDisconnected (crash?): pid=" + pid);
+ unbind(); // We don't want to auto-restart on crash. Let the browser do that.
+ if (pid != 0) {
+ mDeathCallback.onSandboxedProcessDied(pid);
+ }
+ if (onConnectionCallback != null) {
+ onConnectionCallback.run();
+ }
+ }
+
+ /**
+ * Bind the service with a new high priority connection. This will make the service
+ * as important as the main process.
+ */
+ synchronized void bindHighPriority() {
+ if (mService == null) {
+ Log.w(TAG, "The connection is not bound for " + mPID);
+ return;
+ }
+ if (mHighPriorityConnection == null) {
+ mHighPriorityConnection = new HighPriorityConnection();
+ mHighPriorityConnection.bind();
+ }
+ mHighPriorityConnectionCount++;
+ }
+
+ /**
+ * Unbind the service as the high priority connection.
+ */
+ synchronized void unbindHighPriority(boolean force) {
+ if (mService == null) {
+ Log.w(TAG, "The connection is not bound for " + mPID);
+ return;
+ }
+ mHighPriorityConnectionCount--;
+ if (force || (mHighPriorityConnectionCount == 0 && mHighPriorityConnection != null)) {
+ mHighPriorityConnection.unbind();
+ mHighPriorityConnection = null;
+ }
+ }
+
+ private class HighPriorityConnection implements ServiceConnection {
+
+ private boolean mHBound = false;
+
+ void bind() {
+ final Intent intent = createServiceBindIntent();
+
+ mHBound = mContext.bindService(intent, this,
+ Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
+ }
+
+ void unbind() {
+ if (mHBound) {
+ mContext.unbindService(this);
+ mHBound = false;
+ }
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ }
+ }
+
+ /**
+ * @return The connection PID, or 0 if not yet connected.
+ */
+ synchronized public int getPid() {
+ return mPID;
+ }
+}
diff --git a/content/public/android/java/org/chromium/content/common/ISandboxedProcessCallback.aidl b/content/public/android/java/org/chromium/content/common/ISandboxedProcessCallback.aidl
new file mode 100644
index 0000000..72b5535
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/common/ISandboxedProcessCallback.aidl
@@ -0,0 +1,14 @@
+// Copyright (c) 2012 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.
+
+package org.chromium.content.common;
+
+import android.view.Surface;
+
+oneway interface ISandboxedProcessCallback {
+
+ // Conduit to pass a Surface from the sandboxed renderer to the plugin.
+ void establishSurfacePeer(
+ int pid, int type, in Surface surface, int primaryID, int secondaryID);
+}
diff --git a/content/public/android/java/org/chromium/content/common/ISandboxedProcessService.aidl b/content/public/android/java/org/chromium/content/common/ISandboxedProcessService.aidl
new file mode 100644
index 0000000..b8f7da3
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/common/ISandboxedProcessService.aidl
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 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.
+
+package org.chromium.content.common;
+
+import org.chromium.content.common.ISandboxedProcessCallback;
+
+import android.view.Surface;
+import android.os.Bundle;
+
+interface ISandboxedProcessService {
+ // Sets up the initial IPC channel and returns the pid of the sandboxed process.
+ int setupConnection(in Bundle args, ISandboxedProcessCallback callback);
+
+ // Shares the Surface with the sandboxed process.
+ void setSurface(int type, in Surface surface, int primaryID, int secondaryID);
+}
diff --git a/content/public/android/java/org/chromium/content/common/SurfaceCallback.java b/content/public/android/java/org/chromium/content/common/SurfaceCallback.java
new file mode 100644
index 0000000..13ea95b
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/common/SurfaceCallback.java
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 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.
+
+package org.chromium.content.common;
+
+import android.view.Surface;
+
+/* This implements the entry point for passing a Surface handle received through Binder
+ * back to the native code.
+ */
+public class SurfaceCallback {
+ // Calling setSurface passes ownership to the callee and calls release() on the passed in
+ // object.
+ public static void setSurface(int type, Surface surface, int primaryID, int secondaryID) {
+ nativeSetSurface(type, surface, primaryID, secondaryID);
+ }
+
+ /**
+ * Sets up the Surface iBinder for a producer identified by the IDs.
+ *
+ * @param type The install type for the Surface
+ * @param surface The parceled Surface to set.
+ * @param primaryID Used to identify the correct target instance.
+ * @param secondaryID Used to identify the correct target instance.
+ */
+ private static native void nativeSetSurface(int type, Surface surface,
+ int primaryID, int secondaryID);
+}
diff --git a/content/public/android/java/org/chromium/content/common/common.aidl b/content/public/android/java/org/chromium/content/common/common.aidl
new file mode 100644
index 0000000..96ebb7e
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/common/common.aidl
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 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.
+
+// This file is needed to compile ISandBoxedProcessCallback.aidl and
+// ISandboxedProcessServices.aidl into java source files. See
+// content/public/android/java/content.xml for target aidl.
+
+interface org.chromium.content.common.ISandboxedProcessCallback;
+interface org.chromium.content.common.ISandboxedProcessService;
diff --git a/content/public/app/android_library_loader_hooks.h b/content/public/app/android_library_loader_hooks.h
index 596b4a7..515671e 100644
--- a/content/public/app/android_library_loader_hooks.h
+++ b/content/public/app/android_library_loader_hooks.h
@@ -17,6 +17,10 @@ namespace content {
// once the native library has fully loaded.
bool RegisterLibraryLoaderEntryHook(JNIEnv* env);
+// Call on exit to delete the AtExitManager which OnLibraryLoadedOnUIThread
+// created.
+void LibraryLoaderExitHook();
+
} // namespace content
#endif // CONTENT_PUBLIC_APP_ANDROID_LIBRARY_LOADER_HOOKS_H_
diff --git a/content/shell/DEPS b/content/shell/DEPS
index 10563e71..ce20828 100644
--- a/content/shell/DEPS
+++ b/content/shell/DEPS
@@ -10,7 +10,4 @@ include_rules = [
# Shell resources
"+grit/shell_resources.h",
-
- # Include the generated JNI headers
- "+jni",
]
diff --git a/content/shell/android/AndroidManifest.xml b/content/shell/android/AndroidManifest.xml
index c50aa0b..9343c45 100644
--- a/content/shell/android/AndroidManifest.xml
+++ b/content/shell/android/AndroidManifest.xml
@@ -24,9 +24,31 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+ <!-- NOTE: If you change the values of "android:process" for any of the below services,
+ you also need to update kHelperProcessExecutableName in chrome_constants.cc. -->
+ <service android:name="org.chromium.content.app.SanboxedProcessService0"
+ android:process=":sandboxed_process0"
+ android:permission="org.chromium.content_shell.permission.SANDBOX"
+ android:exported="false" />
+ <service android:name="org.chromium.content.app.SanboxedProcessService1"
+ android:process=":sandboxed_process1"
+ android:permission="org.chromium.content_shell.permission.SANDBOX"
+ android:exported="false" />
+ <service android:name="org.chromium.content.app.SanboxedProcessService2"
+ android:process=":sandboxed_process2"
+ android:permission="org.chromium.content_shell.permission.SANDBOX"
+ android:exported="false" />
+ <service android:name="org.chromium.content.app.SanboxedProcessService3"
+ android:process=":sandboxed_process3"
+ android:permission="org.chromium.content_shell.permission.SANDBOX"
+ android:exported="false" />
+ <service android:name="org.chromium.content.app.SanboxedProcessService4"
+ android:process=":sandboxed_process4"
+ android:permission="org.chromium.content_shell.permission.SANDBOX"
+ android:exported="false" />
</application>
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="14" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
-</manifest>
+</manifest>