Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.content.browser; | 5 package org.chromium.content.browser; |
| 6 | 6 |
| 7 import android.content.Context; | 7 import android.content.Context; |
| 8 import android.os.Bundle; | |
| 9 import android.os.IBinder; | |
| 8 import android.os.ParcelFileDescriptor; | 10 import android.os.ParcelFileDescriptor; |
| 9 | 11 |
| 10 import org.chromium.base.ContextUtils; | 12 import org.chromium.base.ContextUtils; |
| 13 import org.chromium.base.CpuFeatures; | |
| 11 import org.chromium.base.Log; | 14 import org.chromium.base.Log; |
| 15 import org.chromium.base.VisibleForTesting; | |
| 12 import org.chromium.base.annotations.CalledByNative; | 16 import org.chromium.base.annotations.CalledByNative; |
| 13 import org.chromium.base.annotations.JNINamespace; | 17 import org.chromium.base.annotations.JNINamespace; |
| 18 import org.chromium.base.library_loader.Linker; | |
| 14 import org.chromium.base.process_launcher.ChildProcessCreationParams; | 19 import org.chromium.base.process_launcher.ChildProcessCreationParams; |
| 15 import org.chromium.base.process_launcher.FileDescriptorInfo; | 20 import org.chromium.base.process_launcher.FileDescriptorInfo; |
| 21 import org.chromium.content.app.ChromiumLinkerParams; | |
| 22 import org.chromium.content.common.ContentSwitches; | |
| 16 | 23 |
| 17 import java.io.IOException; | 24 import java.io.IOException; |
| 18 | 25 |
| 19 /** | 26 /** |
| 20 * This is the java counterpart to ChildProcessLauncherHelper. It is owned by na tive side and | 27 * This is the java counterpart to ChildProcessLauncherHelper. It is owned by na tive side and |
| 21 * has an explicit destroy method. | 28 * has an explicit destroy method. |
| 22 * Each public or jni methods should have explicit documentation on what threads they are called. | 29 * Each public or jni methods should have explicit documentation on what threads they are called. |
| 23 */ | 30 */ |
| 24 @JNINamespace("content::internal") | 31 @JNINamespace("content::internal") |
| 25 class ChildProcessLauncherHelper { | 32 public class ChildProcessLauncherHelper { |
| 26 private static final String TAG = "ChildProcLH"; | 33 private static final String TAG = "ChildProcLH"; |
| 27 | 34 |
| 28 // Represents an invalid process handle; same as base/process/process.h kNul lProcessHandle. | 35 // Represents an invalid process handle; same as base/process/process.h kNul lProcessHandle. |
| 29 private static final int NULL_PROCESS_HANDLE = 0; | 36 private static final int NULL_PROCESS_HANDLE = 0; |
| 30 | 37 |
| 38 // The IBinder provided to the created service. | |
| 39 private final IBinder mIBinderCallback; | |
| 40 | |
| 31 // Note native pointer is only guaranteed live until nativeOnChildProcessSta rted. | 41 // Note native pointer is only guaranteed live until nativeOnChildProcessSta rted. |
| 32 private long mNativeChildProcessLauncherHelper; | 42 private long mNativeChildProcessLauncherHelper; |
| 43 | |
| 44 // The actual service connection. Set once we have connected to the service. | |
| 33 private ChildProcessConnection mChildProcessConnection; | 45 private ChildProcessConnection mChildProcessConnection; |
| 34 | 46 |
| 35 @CalledByNative | 47 @CalledByNative |
| 36 private static FileDescriptorInfo makeFdInfo( | 48 private static FileDescriptorInfo makeFdInfo( |
| 37 int id, int fd, boolean autoClose, long offset, long size) { | 49 int id, int fd, boolean autoClose, long offset, long size) { |
| 38 assert LauncherThread.runningOnLauncherThread(); | 50 assert LauncherThread.runningOnLauncherThread(); |
| 39 ParcelFileDescriptor pFd; | 51 ParcelFileDescriptor pFd; |
| 40 if (autoClose) { | 52 if (autoClose) { |
| 41 // Adopt the FD, it will be closed when we close the ParcelFileDescr iptor. | 53 // Adopt the FD, it will be closed when we close the ParcelFileDescr iptor. |
| 42 pFd = ParcelFileDescriptor.adoptFd(fd); | 54 pFd = ParcelFileDescriptor.adoptFd(fd); |
| 43 } else { | 55 } else { |
| 44 try { | 56 try { |
| 45 pFd = ParcelFileDescriptor.fromFd(fd); | 57 pFd = ParcelFileDescriptor.fromFd(fd); |
| 46 } catch (IOException e) { | 58 } catch (IOException e) { |
| 47 Log.e(TAG, "Invalid FD provided for process connection, aborting connection.", e); | 59 Log.e(TAG, "Invalid FD provided for process connection, aborting connection.", e); |
| 48 return null; | 60 return null; |
| 49 } | 61 } |
| 50 } | 62 } |
| 51 return new FileDescriptorInfo(id, pFd, offset, size); | 63 return new FileDescriptorInfo(id, pFd, offset, size); |
| 52 } | 64 } |
| 53 | 65 |
| 66 @VisibleForTesting | |
| 54 @CalledByNative | 67 @CalledByNative |
| 55 private static ChildProcessLauncherHelper create(long nativePointer, int par amId, | 68 public static ChildProcessLauncherHelper createAndStart(long nativePointer, int paramId, |
| 56 final String[] commandLine, FileDescriptorInfo[] filesToBeMapped) { | 69 final String[] commandLine, FileDescriptorInfo[] filesToBeMapped) { |
| 57 assert LauncherThread.runningOnLauncherThread(); | 70 assert LauncherThread.runningOnLauncherThread(); |
| 58 return new ChildProcessLauncherHelper(nativePointer, paramId, commandLin e, filesToBeMapped); | 71 String processType = |
| 72 ContentSwitches.getSwitchValue(commandLine, ContentSwitches.SWIT CH_PROCESS_TYPE); | |
| 73 | |
| 74 ChildProcessCreationParams params = ChildProcessCreationParams.get(param Id); | |
| 75 if (paramId != ChildProcessCreationParams.DEFAULT_ID && params == null) { | |
| 76 throw new RuntimeException("CreationParams id " + paramId + " not fo und"); | |
| 77 } | |
| 78 | |
| 79 Context context = ContextUtils.getApplicationContext(); | |
| 80 boolean sandboxed = true; | |
| 81 boolean alwaysInForeground = false; | |
| 82 if (!ContentSwitches.SWITCH_RENDERER_PROCESS.equals(processType)) { | |
| 83 if (params != null && !params.getPackageName().equals(context.getPac kageName())) { | |
| 84 // WebViews and WebAPKs have renderer processes running in their applications. | |
| 85 // When launching these renderer processes, {@link ManagedChildP rocessConnection} | |
| 86 // requires the package name of the application which holds the renderer process. | |
| 87 // Therefore, the package name in ChildProcessCreationParams cou ld be the package | |
| 88 // name of WebViews, WebAPKs, or Chrome, depending on the host a pplication. | |
| 89 // Except renderer process, all other child processes should use Chrome's package | |
| 90 // name. In WebAPK, ChildProcessCreationParams are initialized w ith WebAPK's | |
| 91 // package name. Make a copy of the WebAPK's params, but replace the package with | |
| 92 // Chrome's package to use when initializing a non-renderer proc esses. | |
| 93 // TODO(boliu): Should fold into |paramId|. Investigate why this is needed. | |
| 94 params = new ChildProcessCreationParams(context.getPackageName() , | |
| 95 params.getIsExternalService(), params.getLibraryProcessT ype(), | |
| 96 params.getBindToCallerCheck()); | |
| 97 } | |
| 98 if (ContentSwitches.SWITCH_GPU_PROCESS.equals(processType)) { | |
| 99 sandboxed = false; | |
| 100 alwaysInForeground = true; | |
| 101 } else { | |
| 102 // We only support sandboxed utility processes now. | |
| 103 assert ContentSwitches.SWITCH_UTILITY_PROCESS.equals(processType ); | |
| 104 } | |
| 105 } | |
| 106 | |
| 107 ChildProcessLauncherHelper process_launcher = | |
| 108 new ChildProcessLauncherHelper(nativePointer, processType); | |
| 109 process_launcher.start( | |
| 110 context, commandLine, filesToBeMapped, params, sandboxed, always InForeground); | |
| 111 return process_launcher; | |
| 59 } | 112 } |
| 60 | 113 |
| 61 private ChildProcessLauncherHelper(long nativePointer, int paramId, final St ring[] commandLine, | 114 @VisibleForTesting |
| 62 FileDescriptorInfo[] filesToBeMapped) { | 115 public static ChildProcessLauncherHelper createAndStartForTesting(long nativ ePointer, |
|
boliu
2017/05/15 21:38:22
nit: put test-only methods at the very end
Jay Civelli
2017/05/17 16:42:50
Done.
| |
| 116 String[] commandLine, FileDescriptorInfo[] filesToBeMapped, | |
| 117 ChildProcessCreationParams creationParams, boolean sandboxed, | |
| 118 boolean alwaysInForeground) { | |
| 119 String processType = | |
| 120 ContentSwitches.getSwitchValue(commandLine, ContentSwitches.SWIT CH_PROCESS_TYPE); | |
| 121 ChildProcessLauncherHelper launcherHelper = | |
| 122 new ChildProcessLauncherHelper(nativePointer, processType); | |
| 123 launcherHelper.start(ContextUtils.getApplicationContext(), commandLine, filesToBeMapped, | |
| 124 creationParams, sandboxed, alwaysInForeground); | |
| 125 return launcherHelper; | |
| 126 } | |
| 127 | |
| 128 private ChildProcessLauncherHelper(long nativePointer, String processType) { | |
| 63 assert LauncherThread.runningOnLauncherThread(); | 129 assert LauncherThread.runningOnLauncherThread(); |
| 64 mNativeChildProcessLauncherHelper = nativePointer; | 130 mNativeChildProcessLauncherHelper = nativePointer; |
| 131 mIBinderCallback = ContentSwitches.SWITCH_GPU_PROCESS.equals(processType ) | |
| 132 ? new GpuProcessCallback() | |
| 133 : null; | |
| 134 } | |
| 65 | 135 |
| 66 ChildProcessLauncher.start(ContextUtils.getApplicationContext(), paramId , commandLine, | 136 private void start(Context context, String[] commandLine, |
| 67 filesToBeMapped, new ChildProcessLauncher.LaunchCallback() { | 137 final FileDescriptorInfo[] filesToBeMapped, ChildProcessCreationPara ms params, |
| 138 boolean sandboxed, boolean alwaysInForeground) { | |
| 139 boolean bindToCallerCheck = params == null ? false : params.getBindToCal lerCheck(); | |
| 140 Bundle serviceBundle = createServiceBundle(bindToCallerCheck); | |
| 141 onBeforeConnectionAllocated(serviceBundle); | |
| 142 | |
| 143 Bundle connectionBundle = createConnectionBundle(commandLine, filesToBeM apped); | |
| 144 ChildProcessLauncher.start(context, serviceBundle, | |
| 145 connectionBundle, new ChildProcessLauncher.LaunchCallback() { | |
| 68 @Override | 146 @Override |
| 69 public void onChildProcessStarted(ChildProcessConnection con nection) { | 147 public void onChildProcessStarted(ChildProcessConnection con nection) { |
| 70 mChildProcessConnection = connection; | 148 mChildProcessConnection = connection; |
| 71 if (mNativeChildProcessLauncherHelper != 0) { | 149 if (mNativeChildProcessLauncherHelper != 0) { |
| 72 nativeOnChildProcessStarted( | 150 nativeOnChildProcessStarted( |
| 73 mNativeChildProcessLauncherHelper, getPid()) ; | 151 mNativeChildProcessLauncherHelper, getPid()) ; |
| 74 } | 152 } |
| 75 mNativeChildProcessLauncherHelper = 0; | 153 mNativeChildProcessLauncherHelper = 0; |
| 154 // Proactively close the FDs rather than waiting for the GC to do it. | |
| 155 try { | |
|
boliu
2017/05/15 21:38:22
hmm, I guess this is the earliest in this class. B
Jay Civelli
2017/05/17 16:42:50
Done.
| |
| 156 for (FileDescriptorInfo fileInfo : filesToBeMapped) { | |
| 157 fileInfo.fd.close(); | |
| 158 } | |
| 159 } catch (IOException ioe) { | |
| 160 Log.w(TAG, "Failed to close FD.", ioe); | |
| 161 } | |
| 76 } | 162 } |
| 77 }); | 163 }, getIBinderCallback(), sandboxed, alwaysInForeground, params); |
| 78 } | 164 } |
| 79 | 165 |
| 80 private int getPid() { | 166 private int getPid() { |
| 81 return mChildProcessConnection == null ? NULL_PROCESS_HANDLE | 167 return mChildProcessConnection == null ? NULL_PROCESS_HANDLE |
| 82 : mChildProcessConnection.getPid( ); | 168 : mChildProcessConnection.getPid( ); |
| 83 } | 169 } |
| 84 | 170 |
| 85 // Called on client (UI or IO) thread. | 171 // Called on client (UI or IO) thread. |
| 86 @CalledByNative | 172 @CalledByNative |
| 87 private boolean isOomProtected() { | 173 private boolean isOomProtected() { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 123 } catch (RuntimeException e) { | 209 } catch (RuntimeException e) { |
| 124 // Unittest packages do not declare services. Some tests require a r ealistic number | 210 // Unittest packages do not declare services. Some tests require a r ealistic number |
| 125 // to test child process policies, so pick a high-ish number here. | 211 // to test child process policies, so pick a high-ish number here. |
| 126 return 65535; | 212 return 65535; |
| 127 } | 213 } |
| 128 } | 214 } |
| 129 | 215 |
| 130 // Can be called on a number of threads, including launcher, and binder. | 216 // Can be called on a number of threads, including launcher, and binder. |
| 131 private static native void nativeOnChildProcessStarted( | 217 private static native void nativeOnChildProcessStarted( |
| 132 long nativeChildProcessLauncherHelper, int pid); | 218 long nativeChildProcessLauncherHelper, int pid); |
| 219 | |
| 220 private static boolean sLinkerInitialized; | |
| 221 private static long sLinkerLoadAddress; | |
| 222 | |
| 223 private static ChromiumLinkerParams getLinkerParamsForNewConnection() { | |
|
boliu
2017/05/15 21:38:22
static method, can we have a thread assert?
Jay Civelli
2017/05/17 16:42:50
Done.
| |
| 224 if (!sLinkerInitialized) { | |
| 225 if (Linker.isUsed()) { | |
| 226 sLinkerLoadAddress = Linker.getInstance().getBaseLoadAddress(); | |
| 227 if (sLinkerLoadAddress == 0) { | |
| 228 Log.i(TAG, "Shared RELRO support disabled!"); | |
| 229 } | |
| 230 } | |
| 231 sLinkerInitialized = true; | |
| 232 } | |
| 233 | |
| 234 if (sLinkerLoadAddress == 0) return null; | |
| 235 | |
| 236 // Always wait for the shared RELROs in service processes. | |
| 237 final boolean waitForSharedRelros = true; | |
| 238 if (Linker.areTestsEnabled()) { | |
| 239 Linker linker = Linker.getInstance(); | |
| 240 return new ChromiumLinkerParams(sLinkerLoadAddress, waitForSharedRel ros, | |
| 241 linker.getTestRunnerClassNameForTesting(), | |
| 242 linker.getImplementationForTesting()); | |
| 243 } else { | |
| 244 return new ChromiumLinkerParams(sLinkerLoadAddress, waitForSharedRel ros); | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 /** | |
| 249 * Creates the common bundle to be passed to child processes through the ser vice binding intent. | |
| 250 * If the service gets recreated by the framework the intent will be reused, so these parameters | |
| 251 * should be common to all processes of that type. | |
| 252 * | |
| 253 * @param commandLine Command line params to be passed to the service. | |
| 254 * @param linkerParams Linker params to start the service. | |
| 255 */ | |
| 256 // TODO(jcivelli): make private once warmup connection code is move from Chi ldProcessLauncher to | |
| 257 // this class. | |
| 258 static Bundle createServiceBundle(boolean bindToCallerCheck) { | |
| 259 Bundle bundle = new Bundle(); | |
| 260 bundle.putBoolean(ChildProcessConstants.EXTRA_BIND_TO_CALLER, bindToCall erCheck); | |
| 261 return bundle; | |
| 262 } | |
| 263 | |
| 264 @VisibleForTesting | |
| 265 public static Bundle createConnectionBundle( | |
| 266 String[] commandLine, FileDescriptorInfo[] filesToBeMapped) { | |
| 267 Bundle bundle = new Bundle(); | |
| 268 bundle.putStringArray(ChildProcessConstants.EXTRA_COMMAND_LINE, commandL ine); | |
| 269 bundle.putParcelableArray(ChildProcessConstants.EXTRA_FILES, filesToBeMa pped); | |
| 270 // content specific parameters. | |
| 271 bundle.putInt(ChildProcessConstants.EXTRA_CPU_COUNT, CpuFeatures.getCoun t()); | |
| 272 bundle.putLong(ChildProcessConstants.EXTRA_CPU_FEATURES, CpuFeatures.get Mask()); | |
| 273 bundle.putBundle(Linker.EXTRA_LINKER_SHARED_RELROS, Linker.getInstance() .getSharedRelros()); | |
|
boliu
2017/05/15 21:38:22
I don't know this code, but does this need to be o
Jay Civelli
2017/05/17 16:42:50
Good point. Now initializing the Linker in the con
| |
| 274 return bundle; | |
| 275 } | |
| 276 | |
| 277 // Below are methods that will eventually be moved to a content delegate cla ss. | |
| 278 | |
| 279 private void onBeforeConnectionAllocated(Bundle commonParameters) { | |
| 280 // Add content specific parameters. | |
| 281 commonParameters.putParcelable( | |
| 282 ChildProcessConstants.EXTRA_LINKER_PARAMS, getLinkerParamsForNew Connection()); | |
| 283 } | |
| 284 | |
| 285 private IBinder getIBinderCallback() { | |
| 286 return mIBinderCallback; | |
| 287 } | |
| 288 | |
| 289 // Testing only related methods. | |
| 290 @VisibleForTesting | |
| 291 public ChildProcessConnection getChildProcessConnection() { | |
| 292 return mChildProcessConnection; | |
| 293 } | |
| 133 } | 294 } |
| OLD | NEW |