diff options
author | michaelbai@chromium.org <michaelbai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-12 05:00:05 +0000 |
---|---|---|
committer | michaelbai@chromium.org <michaelbai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-12 05:00:05 +0000 |
commit | 5b6f0699827e3dec55b8676bf7893bdab1a1faaa (patch) | |
tree | f44d041a8e35e5e3d6ff0e82f4b768777a4069a8 /content | |
parent | fe655231dca7bbbf0f8ca1299b738c4ef133ee19 (diff) | |
download | chromium_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')
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> |