diff options
author | jcivelli@chromium.org <jcivelli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-25 00:20:08 +0000 |
---|---|---|
committer | jcivelli@chromium.org <jcivelli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-25 00:20:08 +0000 |
commit | c7abd4296309d21002aebb32edf8333ada4f74db (patch) | |
tree | c066a73babc0d66174b9c4828c8726086053bbc3 /content | |
parent | 7c6e9a625f39fe59ff6d846dac353688aa669fee (diff) | |
download | chromium_src-c7abd4296309d21002aebb32edf8333ada4f74db.zip chromium_src-c7abd4296309d21002aebb32edf8333ada4f74db.tar.gz chromium_src-c7abd4296309d21002aebb32edf8333ada4f74db.tar.bz2 |
Close leaking FDs.
When starting a SandboxedProcess the resource file descriptors were leaked in
the browser process, eventually causing crashers.
BUG=None
TEST=When using the Android content shell for a long time, it should not crash.
Review URL: https://chromiumcodereview.appspot.com/10949027
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@158456 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
15 files changed, 206 insertions, 136 deletions
diff --git a/content/app/android/sandboxed_process_service.cc b/content/app/android/sandboxed_process_service.cc index 291748f..eb3c299 100644 --- a/content/app/android/sandboxed_process_service.cc +++ b/content/app/android/sandboxed_process_service.cc @@ -50,22 +50,18 @@ class SurfaceTexturePeerSandboxedImpl : public content::SurfaceTexturePeer { // Chrome actually uses the renderer code path for all of its sandboxed // processes such as renderers, plugins, etc. -void InternalInitSandboxedProcess(int ipc_fd, - const std::vector<int>& extra_file_ids, - const std::vector<int>& extra_file_fds, +void InternalInitSandboxedProcess(const std::vector<int>& file_ids, + const std::vector<int>& file_fds, JNIEnv* env, jclass clazz, jobject context, jobject service) { - // Set up the IPC file descriptor mapping. - base::GlobalDescriptors::GetInstance()->Set(kPrimaryIPCChannel, ipc_fd); - // Register the extra file descriptors. - // This usually include the crash dump signals and resource related files. - DCHECK(extra_file_fds.size() == extra_file_ids.size()); - for (size_t i = 0; i < extra_file_ids.size(); ++i) { - base::GlobalDescriptors::GetInstance()->Set(extra_file_ids[i], - extra_file_fds[i]); - } + // Register the file descriptors. + // This includes the IPC channel, the crash dump signals and resource related + // files. + DCHECK(file_fds.size() == file_ids.size()); + for (size_t i = 0; i < file_ids.size(); ++i) + base::GlobalDescriptors::GetInstance()->Set(file_ids[i], file_fds[i]); content::SurfaceTexturePeer::InitInstance( new SurfaceTexturePeerSandboxedImpl(service)); @@ -80,17 +76,15 @@ void InitSandboxedProcess(JNIEnv* env, jclass clazz, jobject context, jobject service, - jint ipc_fd, - jintArray j_extra_file_ids, - jintArray j_extra_file_fds) { - std::vector<int> extra_file_ids; - std::vector<int> extra_file_fds; - JavaIntArrayToIntVector(env, j_extra_file_ids, &extra_file_ids); - JavaIntArrayToIntVector(env, j_extra_file_fds, &extra_file_fds); - - InternalInitSandboxedProcess(static_cast<int>(ipc_fd), - extra_file_ids, extra_file_fds, - env, clazz, context, service); + jintArray j_file_ids, + jintArray j_file_fds) { + std::vector<int> file_ids; + std::vector<int> file_fds; + JavaIntArrayToIntVector(env, j_file_ids, &file_ids); + JavaIntArrayToIntVector(env, j_file_fds, &file_fds); + + InternalInitSandboxedProcess( + file_ids, file_fds, env, clazz, context, service); } void ExitSandboxedProcess(JNIEnv* env, jclass clazz) { diff --git a/content/browser/android/sandboxed_process_launcher.cc b/content/browser/android/sandboxed_process_launcher.cc index 04d3512..0bdd88a 100644 --- a/content/browser/android/sandboxed_process_launcher.cc +++ b/content/browser/android/sandboxed_process_launcher.cc @@ -13,7 +13,6 @@ using base::android::AttachCurrentThread; using base::android::ToJavaArrayOfStrings; using base::android::ScopedJavaLocalRef; -using base::GlobalDescriptors; using content::StartSandboxedProcessCallback; namespace content { @@ -37,8 +36,7 @@ static void OnSandboxedProcessStarted(JNIEnv*, void StartSandboxedProcess( const CommandLine::StringVector& argv, - int ipc_fd, - const GlobalDescriptors::Mapping& files_to_register, + const std::vector<content::FileDescriptorInfo>& files_to_register, const StartSandboxedProcessCallback& callback) { JNIEnv* env = AttachCurrentThread(); DCHECK(env); @@ -46,24 +44,40 @@ void StartSandboxedProcess( // Create the Command line String[] ScopedJavaLocalRef<jobjectArray> j_argv = ToJavaArrayOfStrings(env, argv); - ScopedJavaLocalRef<jintArray> j_file_to_register_id_files(env, - env->NewIntArray(files_to_register.size() * 2)); - scoped_array<jint> file_to_register_id_files( - new jint[files_to_register.size() * 2]); - for (size_t i = 0; i < files_to_register.size(); ++i) { - const GlobalDescriptors::KeyFDPair& id_file = files_to_register[i]; - file_to_register_id_files[2 * i] = id_file.first; - file_to_register_id_files[(2 * i) + 1] = id_file.second; + size_t file_count = files_to_register.size(); + DCHECK(file_count > 0); + + ScopedJavaLocalRef<jintArray> j_file_ids(env, env->NewIntArray(file_count)); + base::android::CheckException(env); + jint* file_ids = env->GetIntArrayElements(j_file_ids.obj(), NULL); + base::android::CheckException(env); + ScopedJavaLocalRef<jintArray> j_file_fds(env, env->NewIntArray(file_count)); + base::android::CheckException(env); + jint* file_fds = env->GetIntArrayElements(j_file_fds.obj(), NULL); + base::android::CheckException(env); + ScopedJavaLocalRef<jbooleanArray> j_file_auto_close( + env, env->NewBooleanArray(file_count)); + base::android::CheckException(env); + jboolean* file_auto_close = + env->GetBooleanArrayElements(j_file_auto_close.obj(), NULL); + base::android::CheckException(env); + for (size_t i = 0; i < file_count; ++i) { + const content::FileDescriptorInfo& fd_info = files_to_register[i]; + file_ids[i] = fd_info.id; + file_fds[i] = fd_info.fd.fd; + file_auto_close[i] = fd_info.fd.auto_close; } - env->SetIntArrayRegion(j_file_to_register_id_files.obj(), - 0, files_to_register.size() * 2, - file_to_register_id_files.get()); + env->ReleaseIntArrayElements(j_file_ids.obj(), file_ids, 0); + env->ReleaseIntArrayElements(j_file_fds.obj(), file_fds, 0); + env->ReleaseBooleanArrayElements(j_file_auto_close.obj(), file_auto_close, 0); + Java_SandboxedProcessLauncher_start(env, - base::android::GetApplicationContext(), - static_cast<jobjectArray>(j_argv.obj()), - static_cast<jint>(ipc_fd), - j_file_to_register_id_files.obj(), - reinterpret_cast<jint>(new StartSandboxedProcessCallback(callback))); + base::android::GetApplicationContext(), + j_argv.obj(), + j_file_ids.obj(), + j_file_fds.obj(), + j_file_auto_close.obj(), + reinterpret_cast<jint>(new StartSandboxedProcessCallback(callback))); } void StopSandboxedProcess(base::ProcessHandle handle) { diff --git a/content/browser/android/sandboxed_process_launcher.h b/content/browser/android/sandboxed_process_launcher.h index 13b36da..64deaac 100644 --- a/content/browser/android/sandboxed_process_launcher.h +++ b/content/browser/android/sandboxed_process_launcher.h @@ -9,9 +9,9 @@ #include "base/callback.h" #include "base/command_line.h" -#include "base/global_descriptors_posix.h" #include "base/platform_file.h" #include "base/process.h" +#include "content/public/browser/file_descriptor_info.h" namespace content { @@ -22,8 +22,7 @@ typedef base::Callback<void(base::ProcessHandle)> StartSandboxedProcessCallback; // retuned if the process could not be created. void StartSandboxedProcess( const CommandLine::StringVector& argv, - int ipc_fd, - const base::GlobalDescriptors::Mapping& files_to_register, + const std::vector<FileDescriptorInfo>& files_to_register, const StartSandboxedProcessCallback& callback); // Stops a sandboxed process based on the handle returned form diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc index f7cf772..0bbc035 100644 --- a/content/browser/child_process_launcher.cc +++ b/content/browser/child_process_launcher.cc @@ -166,28 +166,31 @@ class ChildProcessLauncher::Context #elif defined(OS_ANDROID) std::string process_type = cmd_line->GetSwitchValueASCII(switches::kProcessType); - base::GlobalDescriptors::Mapping files_to_register; - files_to_register.push_back(std::pair<base::GlobalDescriptors::Key, int>( - kPrimaryIPCChannel, ipcfd)); + std::vector<content::FileDescriptorInfo> files_to_register; + files_to_register.push_back( + content::FileDescriptorInfo(kPrimaryIPCChannel, + base::FileDescriptor(ipcfd, false))); + content::GetContentClient()->browser()-> GetAdditionalMappedFilesForChildProcess(*cmd_line, &files_to_register); - content::StartSandboxedProcess(cmd_line->argv(), - ipcfd, files_to_register, + content::StartSandboxedProcess(cmd_line->argv(), files_to_register, base::Bind(&ChildProcessLauncher::Context::OnSandboxedProcessStarted, this_object, client_thread_id)); #elif defined(OS_POSIX) base::ProcessHandle handle = base::kNullProcessHandle; - // We need to close the client end of the IPC channel - // to reliably detect child termination. + // We need to close the client end of the IPC channel to reliably detect + // child termination. file_util::ScopedFD ipcfd_closer(&ipcfd); std::string process_type = cmd_line->GetSwitchValueASCII(switches::kProcessType); - base::GlobalDescriptors::Mapping files_to_register; - files_to_register.push_back(std::pair<base::GlobalDescriptors::Key, int>( - kPrimaryIPCChannel, ipcfd)); + std::vector<content::FileDescriptorInfo> files_to_register; + files_to_register.push_back( + content::FileDescriptorInfo(kPrimaryIPCChannel, + base::FileDescriptor(ipcfd, false))); + #if !defined(OS_MACOSX) content::GetContentClient()->browser()-> GetAdditionalMappedFilesForChildProcess(*cmd_line, &files_to_register); @@ -201,12 +204,12 @@ class ChildProcessLauncher::Context { // Convert FD mapping to FileHandleMappingVector base::FileHandleMappingVector fds_to_map; - for (size_t i = 0; i < files_to_register.size(); ++i) { - const base::GlobalDescriptors::KeyFDPair& id_file = - files_to_register[i]; + for (std::vector<content::FileDescriptorInfo>::const_iterator + i = files_to_register.begin(); i != files_to_register.end(); ++i) { + const content::FileDescriptorInfo& fd_info = *i; fds_to_map.push_back(std::make_pair( - id_file.second, - id_file.first + base::GlobalDescriptors::kBaseDescriptor)); + fd_info.fd.fd, + fd_info.id + base::GlobalDescriptors::kBaseDescriptor)); } #if !defined(OS_MACOSX) diff --git a/content/browser/zygote_host/zygote_host_impl_linux.cc b/content/browser/zygote_host/zygote_host_impl_linux.cc index 6ef5487..7d084ac 100644 --- a/content/browser/zygote_host/zygote_host_impl_linux.cc +++ b/content/browser/zygote_host/zygote_host_impl_linux.cc @@ -16,6 +16,7 @@ #include "base/file_util.h" #include "base/linux_util.h" #include "base/logging.h" +#include "base/memory/linked_ptr.h" #include "base/memory/scoped_ptr.h" #include "base/metrics/histogram.h" #include "base/path_service.h" @@ -238,7 +239,7 @@ ssize_t ZygoteHostImpl::ReadReply(void* buf, size_t buf_len) { pid_t ZygoteHostImpl::ForkRequest( const std::vector<std::string>& argv, - const base::GlobalDescriptors::Mapping& mapping, + const std::vector<content::FileDescriptorInfo>& mapping, const std::string& process_type) { DCHECK(init_); Pickle pickle; @@ -253,10 +254,20 @@ pid_t ZygoteHostImpl::ForkRequest( pickle.WriteInt(mapping.size()); std::vector<int> fds; - for (base::GlobalDescriptors::Mapping::const_iterator + // Scoped pointers cannot be stored in containers, so we have to use a + // linked_ptr. + std::vector<linked_ptr<file_util::ScopedFD> > autodelete_fds; + for (std::vector<content::FileDescriptorInfo>::const_iterator i = mapping.begin(); i != mapping.end(); ++i) { - pickle.WriteUInt32(i->first); - fds.push_back(i->second); + pickle.WriteUInt32(i->id); + fds.push_back(i->fd.fd); + if (i->fd.auto_close) { + // Auto-close means we need to close the FDs after they habe been passed + // to the other process. + linked_ptr<file_util::ScopedFD> ptr( + new file_util::ScopedFD(&(fds.back()))); + autodelete_fds.push_back(ptr); + } } pid_t pid; diff --git a/content/browser/zygote_host/zygote_host_impl_linux.h b/content/browser/zygote_host/zygote_host_impl_linux.h index 17a6b35..460abc5 100644 --- a/content/browser/zygote_host/zygote_host_impl_linux.h +++ b/content/browser/zygote_host/zygote_host_impl_linux.h @@ -8,9 +8,9 @@ #include <string> #include <vector> -#include "base/global_descriptors_posix.h" #include "base/process_util.h" #include "base/synchronization/lock.h" +#include "content/public/browser/file_descriptor_info.h" #include "content/public/browser/zygote_host_linux.h" template<typename Type> @@ -27,7 +27,7 @@ class CONTENT_EXPORT ZygoteHostImpl : public content::ZygoteHost { // Returns its pid on success, otherwise // base::kNullProcessHandle; pid_t ForkRequest(const std::vector<std::string>& command_line, - const base::GlobalDescriptors::Mapping& mapping, + const std::vector<content::FileDescriptorInfo>& mapping, const std::string& process_type); void EnsureProcessTerminated(pid_t process); diff --git a/content/content_browser.gypi b/content/content_browser.gypi index 1d01015..ed37f1b 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -75,6 +75,7 @@ 'public/browser/download_url_parameters.h', 'public/browser/favicon_status.cc', 'public/browser/favicon_status.h', + 'public/browser/file_descriptor_info.h', 'public/browser/font_list_async.h', 'public/browser/geolocation.h', 'public/browser/geolocation_permission_context.h', diff --git a/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService.java b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService.java index 4ce68ed..5917736 100644 --- a/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService.java +++ b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService.java @@ -47,10 +47,9 @@ public class SandboxedProcessService extends Service { // Parameters received via IPC, only accessed while holding the mSandboxMainThread monitor. private String mNativeLibraryName; // Must be passed in via the bind command. private String[] mCommandLineParams; - private ParcelFileDescriptor mIPCFd; // Pairs IDs and file descriptors that should be registered natively. - private ArrayList<Integer> mExtraFileIds; - private ArrayList<ParcelFileDescriptor> mExtraFileFds; + private ArrayList<Integer> mFileIds; + private ArrayList<ParcelFileDescriptor> mFileFds; private static Context sContext = null; private boolean mLibraryInitialized = false; @@ -70,9 +69,8 @@ public class SandboxedProcessService extends Service { } // We must have received the command line by now assert mCommandLineParams != null; - mIPCFd = args.getParcelable(SandboxedProcessConnection.EXTRA_IPC_FD); - mExtraFileIds = new ArrayList<Integer>(); - mExtraFileFds = new ArrayList<ParcelFileDescriptor>(); + mFileIds = new ArrayList<Integer>(); + mFileFds = new ArrayList<ParcelFileDescriptor>(); for (int i = 0;; i++) { String fdName = SandboxedProcessConnection.EXTRA_FILES_PREFIX + i + SandboxedProcessConnection.EXTRA_FILES_FD_SUFFIX; @@ -81,10 +79,10 @@ public class SandboxedProcessService extends Service { // End of the file list. break; } - mExtraFileFds.add(parcel); + mFileFds.add(parcel); String idName = SandboxedProcessConnection.EXTRA_FILES_PREFIX + i + SandboxedProcessConnection.EXTRA_FILES_ID_SUFFIX; - mExtraFileIds.add(args.getInt(idName)); + mFileIds.add(args.getInt(idName)); } mSandboxMainThread.notifyAll(); } @@ -127,21 +125,20 @@ public class SandboxedProcessService extends Service { synchronized (mSandboxMainThread) { mLibraryInitialized = true; mSandboxMainThread.notifyAll(); - while (mIPCFd == null) { + while (mFileIds == null) { mSandboxMainThread.wait(); } } - assert mExtraFileIds.size() == mExtraFileFds.size(); - int[] extraFileIds = new int[mExtraFileIds.size()]; - int[] extraFileFds = new int[mExtraFileFds.size()]; - for (int i = 0; i < mExtraFileIds.size(); ++i) { - extraFileIds[i] = mExtraFileIds.get(i); - extraFileFds[i] = mExtraFileFds.get(i).detachFd(); + assert mFileIds.size() == mFileFds.size(); + int[] fileIds = new int[mFileIds.size()]; + int[] fileFds = new int[mFileFds.size()]; + for (int i = 0; i < mFileIds.size(); ++i) { + fileIds[i] = mFileIds.get(i); + fileFds[i] = mFileFds.get(i).detachFd(); } ContentMain.initApplicationContext(sContext.getApplicationContext()); nativeInitSandboxedProcess(sContext.getApplicationContext(), - SandboxedProcessService.this, mIPCFd.detachFd(), - extraFileIds, extraFileFds); + SandboxedProcessService.this, fileIds, fileFds); ContentMain.start(); nativeExitSandboxedProcess(); } catch (InterruptedException e) { @@ -246,14 +243,12 @@ public class SandboxedProcessService extends Service { * * @param applicationContext The Application Context of the current process. * @param service The current SandboxedProcessService object. - * @param ipcFd File descriptor to use for ipc. - * @param extraFileIds (Optional) A list of pair of file IDs that should be registered for - * access by the renderer. - * @param extraFileFds (Optional) A list of pair of file descriptors that should be registered - * for access by the renderer. + * @param fileIds A list of file IDs that should be registered for access by the renderer. + * @param fileFds A list of file descriptors that should be registered for access by the + * renderer. */ private static native void nativeInitSandboxedProcess(Context applicationContext, - SandboxedProcessService service, int ipcFd, int[] extraFileIds, int[] extraFileFds); + SandboxedProcessService service, int[] extraFileIds, int[] extraFileFds); /** * Force the sandboxed process to exit. diff --git a/content/public/android/java/src/org/chromium/content/browser/FileDescriptorInfo.java b/content/public/android/java/src/org/chromium/content/browser/FileDescriptorInfo.java new file mode 100644 index 0000000..a0db0b9 --- /dev/null +++ b/content/public/android/java/src/org/chromium/content/browser/FileDescriptorInfo.java @@ -0,0 +1,20 @@ +// 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 org.chromium.base.CalledByNative; +import org.chromium.base.JNINamespace; + +class FileDescriptorInfo { + public int mId; + public int mFd; + public boolean mAutoClose; + + FileDescriptorInfo(int id, int fd, boolean autoClose) { + mId = id; + mFd = fd; + mAutoClose = autoClose; + } +}
\ No newline at end of file diff --git a/content/public/android/java/src/org/chromium/content/browser/SandboxedProcessConnection.java b/content/public/android/java/src/org/chromium/content/browser/SandboxedProcessConnection.java index e6376b8..d334751 100644 --- a/content/public/android/java/src/org/chromium/content/browser/SandboxedProcessConnection.java +++ b/content/public/android/java/src/org/chromium/content/browser/SandboxedProcessConnection.java @@ -36,8 +36,7 @@ public class SandboxedProcessConnection implements ServiceConnection { "com.google.android.apps.chrome.extra.sandbox_command_line"; public static final String EXTRA_NATIVE_LIBRARY_NAME = "com.google.android.apps.chrome.extra.sandbox_native_library_name"; - // 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"; + // Note the FDs may only be passed in the connection bundle. public static final String EXTRA_FILES_PREFIX = "com.google.android.apps.chrome.extra.sandbox_extraFile_"; public static final String EXTRA_FILES_ID_SUFFIX = "_id"; @@ -61,20 +60,17 @@ public class SandboxedProcessConnection implements ServiceConnection { private static class ConnectionParams { final String[] mCommandLine; - final int mIpcFd; - final int[] mExtraFileIdsAndFds; + final FileDescriptorInfo[] mFilesToBeMapped; final ISandboxedProcessCallback mCallback; final Runnable mOnConnectionCallback; ConnectionParams( String[] commandLine, - int ipcFd, - int[] idsAndFds, + FileDescriptorInfo[] filesToBeMapped, ISandboxedProcessCallback callback, Runnable onConnectionCallback) { mCommandLine = commandLine; - mIpcFd = ipcFd; - mExtraFileIdsAndFds = idsAndFds; + mFilesToBeMapped = filesToBeMapped; mCallback = callback; mOnConnectionCallback = onConnectionCallback; } @@ -139,21 +135,18 @@ public class SandboxedProcessConnection implements ServiceConnection { * * 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 fileToRegisterIdFds (Optional) a list of pair of IDs and FDs that should be - * registered + * @param fileToBeMapped a list of file descriptors that should be registered * @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[] fileToRegisterIdFds, + FileDescriptorInfo[] filesToBeMapped, ISandboxedProcessCallback callback, Runnable onConnectionCallback) { TraceEvent.begin(); assert mConnectionParams == null; - mConnectionParams = new ConnectionParams(commandLine, ipcFd, fileToRegisterIdFds, callback, + mConnectionParams = new ConnectionParams(commandLine, filesToBeMapped, callback, onConnectionCallback); if (mServiceConnectComplete) { doConnectionSetup(); @@ -213,43 +206,43 @@ public class SandboxedProcessConnection implements ServiceConnection { if (onConnectionCallback == null) { unbind(); } else if (mService != null) { - ParcelFileDescriptor ipcFdParcel; - try { - ipcFdParcel = ParcelFileDescriptor.fromFd(mConnectionParams.mIpcFd); - } catch(IOException e) { - Log.e(TAG, "Invalid IPC FD, aborting connection.", e); - return; - } Bundle bundle = new Bundle(); bundle.putStringArray(EXTRA_COMMAND_LINE, mConnectionParams.mCommandLine); - bundle.putParcelable(EXTRA_IPC_FD, ipcFdParcel); - int[] idsAndFds = mConnectionParams.mExtraFileIdsAndFds; - assert idsAndFds.length % 2 == 0; - int pairLength = idsAndFds.length / 2; - for (int i = 0; i < pairLength; i++) { + FileDescriptorInfo[] fileInfos = mConnectionParams.mFilesToBeMapped; + ParcelFileDescriptor[] parcelFiles = new ParcelFileDescriptor[fileInfos.length]; + for (int i = 0; i < fileInfos.length; i++) { String idName = EXTRA_FILES_PREFIX + i + EXTRA_FILES_ID_SUFFIX; String fdName = EXTRA_FILES_PREFIX + i + EXTRA_FILES_FD_SUFFIX; - ParcelFileDescriptor parcelFile; - try { - parcelFile = ParcelFileDescriptor.fromFd(idsAndFds[(2 * i) + 1]); - bundle.putParcelable(fdName, parcelFile); - bundle.putInt(idName, idsAndFds[2 * i]); - } catch (IOException e) { - Log.e(TAG, "Invalid extra file FD: id=" + idsAndFds[ 2 * i] + " fd=" - + idsAndFds[(2 * i) + 1]); + if (fileInfos[i].mAutoClose) { + // Adopt the FD, it will be closed when we close the ParcelFileDescriptor. + parcelFiles[i] = ParcelFileDescriptor.adoptFd(fileInfos[i].mFd); + } else { + try { + parcelFiles[i] = ParcelFileDescriptor.fromFd(fileInfos[i].mFd); + } catch(IOException e) { + Log.e(TAG, + "Invalid FD provided for process connection, aborting connection.", + e); + return; + } + } + bundle.putParcelable(fdName, parcelFiles[i]); + bundle.putInt(idName, fileInfos[i].mId); } try { mPID = mService.setupConnection(bundle, mConnectionParams.mCallback); } catch (android.os.RemoteException re) { Log.e(TAG, "Failed to setup connection.", re); } + // We proactivley close the FDs rather than wait for GC & finalizer. try { - // We proactivley close now rather than wait for GC & finalizer. - ipcFdParcel.close(); + for (ParcelFileDescriptor parcelFile : parcelFiles) { + if (parcelFile != null) parcelFile.close(); + } } catch (IOException ioe) { - Log.w(TAG, "Failed to close IPC FD.", ioe); + Log.w(TAG, "Failed to close FD.", ioe); } } mConnectionParams = null; diff --git a/content/public/android/java/src/org/chromium/content/browser/SandboxedProcessLauncher.java b/content/public/android/java/src/org/chromium/content/browser/SandboxedProcessLauncher.java index f1913ff..766eca3 100644 --- a/content/public/android/java/src/org/chromium/content/browser/SandboxedProcessLauncher.java +++ b/content/public/android/java/src/org/chromium/content/browser/SandboxedProcessLauncher.java @@ -161,16 +161,26 @@ public class SandboxedProcessLauncher { * * @param context Context used to obtain the application context. * @param commandLine The sandboxed process command line argv. - * @param ipcFd File descriptor used to set up IPC. + * @param file_ids The ID that should be used when mapping files in the created process. + * @param file_fds The file descriptors that should be mapped in the created process. + * @param file_auto_close Whether the file descriptors should be closed once they were passed to + * the created process. * @param clientContext Arbitrary parameter used by the client to distinguish this connection. */ @CalledByNative static void start( Context context, final String[] commandLine, - int ipcFd, - int[] fileToRegisterIdFds, + int[] fileIds, + int[] fileFds, + boolean[] fileAutoClose, final int clientContext) { + assert fileIds.length == fileFds.length && fileFds.length == fileAutoClose.length; + FileDescriptorInfo[] filesToBeMapped = new FileDescriptorInfo[fileFds.length]; + for (int i = 0; i < fileFds.length; i++) { + filesToBeMapped[i] = + new FileDescriptorInfo(fileIds[i], fileFds[i], fileAutoClose[i]); + } assert clientContext != 0; SandboxedProcessConnection allocatedConnection; synchronized (SandboxedProcessLauncher.class) { @@ -201,8 +211,7 @@ public class SandboxedProcessLauncher { nativeOnSandboxedProcessStarted(clientContext, pid); } }; - connection.setupConnection(commandLine, ipcFd, fileToRegisterIdFds, createCallback(), - onConnect); + connection.setupConnection(commandLine, filesToBeMapped, createCallback(), onConnect); } /** diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index 7766f55..7c55235 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h @@ -10,6 +10,7 @@ #include <vector> #include "base/callback_forward.h" +#include "content/public/browser/file_descriptor_info.h" #include "content/public/common/content_client.h" #include "content/public/common/window_container_type.h" #include "net/cookies/canonical_cookie.h" @@ -453,7 +454,7 @@ class CONTENT_EXPORT ContentBrowserClient { // a child process. virtual void GetAdditionalMappedFilesForChildProcess( const CommandLine& command_line, - base::GlobalDescriptors::Mapping* mappings) {} + std::vector<FileDescriptorInfo>* mappings) {} #endif #if defined(OS_WIN) diff --git a/content/public/browser/file_descriptor_info.h b/content/public/browser/file_descriptor_info.h new file mode 100644 index 0000000..2248eb6 --- /dev/null +++ b/content/public/browser/file_descriptor_info.h @@ -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. + +#ifndef CONTENT_PUBLIC_BROWSER_FILE_DESCRIPTOR_INFO_H_ +#define CONTENT_PUBLIC_BROWSER_FILE_DESCRIPTOR_INFO_H_ + +#include "base/file_descriptor_posix.h" + +namespace content { + +// This struct is used when passing files that should be mapped in a process +// that is been created and allows to associate that file with a specific ID. +// It also provides a way to know if the actual file descriptor should be +// closed with the FileDescriptor.auto_close field. + +struct FileDescriptorInfo { + FileDescriptorInfo(int id, const base::FileDescriptor& file_descriptor) + : id(id), + fd(file_descriptor) { + } + + int id; + base::FileDescriptor fd; +}; + +} + +#endif // CONTENT_PUBLIC_BROWSER_FILE_DESCRIPTOR_INFO_H_ diff --git a/content/shell/shell_content_browser_client.cc b/content/shell/shell_content_browser_client.cc index c2fd53c..e07287a 100644 --- a/content/shell/shell_content_browser_client.cc +++ b/content/shell/shell_content_browser_client.cc @@ -76,7 +76,7 @@ WebContentsViewDelegate* ShellContentBrowserClient::GetWebContentsViewDelegate( #if defined(OS_ANDROID) void ShellContentBrowserClient::GetAdditionalMappedFilesForChildProcess( const CommandLine& command_line, - base::GlobalDescriptors::Mapping* mappings) { + std::vector<content::FileDescriptorInfo>* mappings) { int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ; FilePath pak_file; DCHECK(PathService::Get(base::DIR_ANDROID_APP_DATA, &pak_file)); @@ -89,8 +89,9 @@ void ShellContentBrowserClient::GetAdditionalMappedFilesForChildProcess( NOTREACHED() << "Failed to open file when creating renderer process: " << "content_shell.pak"; } - mappings->push_back(std::pair<base::GlobalDescriptors::Key, int>( - kShellPakDescriptor, f)); + mappings->push_back( + content::FileDescriptorInfo(kShellPakDescriptor, + base::FileDescriptor(f, true))); } #endif diff --git a/content/shell/shell_content_browser_client.h b/content/shell/shell_content_browser_client.h index 1cf3915..0a5ef05 100644 --- a/content/shell/shell_content_browser_client.h +++ b/content/shell/shell_content_browser_client.h @@ -38,7 +38,7 @@ class ShellContentBrowserClient : public ContentBrowserClient { #if defined(OS_ANDROID) virtual void GetAdditionalMappedFilesForChildProcess( const CommandLine& command_line, - base::GlobalDescriptors::Mapping* mappings) OVERRIDE; + std::vector<content::FileDescriptorInfo>* mappings) OVERRIDE; #endif ShellBrowserContext* browser_context(); |