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 private ChildProcessLauncherHelper(long nativePointer, String processType) { |
62 FileDescriptorInfo[] filesToBeMapped) { | |
63 assert LauncherThread.runningOnLauncherThread(); | 115 assert LauncherThread.runningOnLauncherThread(); |
64 mNativeChildProcessLauncherHelper = nativePointer; | 116 mNativeChildProcessLauncherHelper = nativePointer; |
| 117 mIBinderCallback = ContentSwitches.SWITCH_GPU_PROCESS.equals(processType
) |
| 118 ? new GpuProcessCallback() |
| 119 : null; |
| 120 initLinker(); |
| 121 } |
65 | 122 |
66 ChildProcessLauncher.start(ContextUtils.getApplicationContext(), paramId
, commandLine, | 123 private void start(Context context, String[] commandLine, |
67 filesToBeMapped, new ChildProcessLauncher.LaunchCallback() { | 124 final FileDescriptorInfo[] filesToBeMapped, ChildProcessCreationPara
ms params, |
| 125 boolean sandboxed, boolean alwaysInForeground) { |
| 126 boolean bindToCallerCheck = params == null ? false : params.getBindToCal
lerCheck(); |
| 127 Bundle serviceBundle = createServiceBundle(bindToCallerCheck); |
| 128 onBeforeConnectionAllocated(serviceBundle); |
| 129 |
| 130 Bundle connectionBundle = createConnectionBundle(commandLine, filesToBeM
apped); |
| 131 ChildProcessLauncher.start(context, serviceBundle, |
| 132 connectionBundle, new ChildProcessLauncher.LaunchCallback() { |
68 @Override | 133 @Override |
69 public void onChildProcessStarted(ChildProcessConnection con
nection) { | 134 public void onChildProcessStarted(ChildProcessConnection con
nection) { |
70 mChildProcessConnection = connection; | 135 mChildProcessConnection = connection; |
| 136 |
| 137 // Proactively close the FDs rather than waiting for the
GC to do it. |
| 138 try { |
| 139 for (FileDescriptorInfo fileInfo : filesToBeMapped)
{ |
| 140 fileInfo.fd.close(); |
| 141 } |
| 142 } catch (IOException ioe) { |
| 143 Log.w(TAG, "Failed to close FD.", ioe); |
| 144 } |
| 145 |
71 if (mNativeChildProcessLauncherHelper != 0) { | 146 if (mNativeChildProcessLauncherHelper != 0) { |
72 nativeOnChildProcessStarted( | 147 nativeOnChildProcessStarted( |
73 mNativeChildProcessLauncherHelper, getPid())
; | 148 mNativeChildProcessLauncherHelper, getPid())
; |
74 } | 149 } |
75 mNativeChildProcessLauncherHelper = 0; | 150 mNativeChildProcessLauncherHelper = 0; |
76 } | 151 } |
77 }); | 152 }, getIBinderCallback(), sandboxed, alwaysInForeground, params); |
78 } | 153 } |
79 | 154 |
80 private int getPid() { | 155 private int getPid() { |
81 return mChildProcessConnection == null ? NULL_PROCESS_HANDLE | 156 return mChildProcessConnection == null ? NULL_PROCESS_HANDLE |
82 : mChildProcessConnection.getPid(
); | 157 : mChildProcessConnection.getPid(
); |
83 } | 158 } |
84 | 159 |
85 // Called on client (UI or IO) thread. | 160 // Called on client (UI or IO) thread. |
86 @CalledByNative | 161 @CalledByNative |
87 private boolean isOomProtected() { | 162 private boolean isOomProtected() { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 } catch (RuntimeException e) { | 198 } catch (RuntimeException e) { |
124 // Unittest packages do not declare services. Some tests require a r
ealistic number | 199 // 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. | 200 // to test child process policies, so pick a high-ish number here. |
126 return 65535; | 201 return 65535; |
127 } | 202 } |
128 } | 203 } |
129 | 204 |
130 // Can be called on a number of threads, including launcher, and binder. | 205 // Can be called on a number of threads, including launcher, and binder. |
131 private static native void nativeOnChildProcessStarted( | 206 private static native void nativeOnChildProcessStarted( |
132 long nativeChildProcessLauncherHelper, int pid); | 207 long nativeChildProcessLauncherHelper, int pid); |
| 208 |
| 209 private static boolean sLinkerInitialized; |
| 210 private static long sLinkerLoadAddress; |
| 211 @VisibleForTesting |
| 212 static void initLinker() { |
| 213 assert LauncherThread.runningOnLauncherThread(); |
| 214 if (sLinkerInitialized) return; |
| 215 if (Linker.isUsed()) { |
| 216 sLinkerLoadAddress = Linker.getInstance().getBaseLoadAddress(); |
| 217 if (sLinkerLoadAddress == 0) { |
| 218 Log.i(TAG, "Shared RELRO support disabled!"); |
| 219 } |
| 220 } |
| 221 sLinkerInitialized = true; |
| 222 } |
| 223 |
| 224 private static ChromiumLinkerParams getLinkerParamsForNewConnection() { |
| 225 assert LauncherThread.runningOnLauncherThread(); |
| 226 assert sLinkerInitialized; |
| 227 |
| 228 if (sLinkerLoadAddress == 0) return null; |
| 229 |
| 230 // Always wait for the shared RELROs in service processes. |
| 231 final boolean waitForSharedRelros = true; |
| 232 if (Linker.areTestsEnabled()) { |
| 233 Linker linker = Linker.getInstance(); |
| 234 return new ChromiumLinkerParams(sLinkerLoadAddress, waitForSharedRel
ros, |
| 235 linker.getTestRunnerClassNameForTesting(), |
| 236 linker.getImplementationForTesting()); |
| 237 } else { |
| 238 return new ChromiumLinkerParams(sLinkerLoadAddress, waitForSharedRel
ros); |
| 239 } |
| 240 } |
| 241 |
| 242 /** |
| 243 * Creates the common bundle to be passed to child processes through the ser
vice binding intent. |
| 244 * If the service gets recreated by the framework the intent will be reused,
so these parameters |
| 245 * should be common to all processes of that type. |
| 246 * |
| 247 * @param commandLine Command line params to be passed to the service. |
| 248 * @param linkerParams Linker params to start the service. |
| 249 */ |
| 250 // TODO(jcivelli): make private once warmup connection code is move from Chi
ldProcessLauncher to |
| 251 // this class and remove initLinker call. |
| 252 static Bundle createServiceBundle(boolean bindToCallerCheck) { |
| 253 initLinker(); |
| 254 Bundle bundle = new Bundle(); |
| 255 bundle.putBoolean(ChildProcessConstants.EXTRA_BIND_TO_CALLER, bindToCall
erCheck); |
| 256 bundle.putParcelable( |
| 257 ChildProcessConstants.EXTRA_LINKER_PARAMS, getLinkerParamsForNew
Connection()); |
| 258 return bundle; |
| 259 } |
| 260 |
| 261 @VisibleForTesting |
| 262 public static Bundle createConnectionBundle( |
| 263 String[] commandLine, FileDescriptorInfo[] filesToBeMapped) { |
| 264 assert sLinkerInitialized; |
| 265 |
| 266 Bundle bundle = new Bundle(); |
| 267 bundle.putStringArray(ChildProcessConstants.EXTRA_COMMAND_LINE, commandL
ine); |
| 268 bundle.putParcelableArray(ChildProcessConstants.EXTRA_FILES, filesToBeMa
pped); |
| 269 // content specific parameters. |
| 270 bundle.putInt(ChildProcessConstants.EXTRA_CPU_COUNT, CpuFeatures.getCoun
t()); |
| 271 bundle.putLong(ChildProcessConstants.EXTRA_CPU_FEATURES, CpuFeatures.get
Mask()); |
| 272 bundle.putBundle(Linker.EXTRA_LINKER_SHARED_RELROS, Linker.getInstance()
.getSharedRelros()); |
| 273 return bundle; |
| 274 } |
| 275 |
| 276 // Below are methods that will eventually be moved to a content delegate cla
ss. |
| 277 |
| 278 private void onBeforeConnectionAllocated(Bundle commonParameters) { |
| 279 // TODO(jcivelli): move createServiceBundle in there. |
| 280 } |
| 281 |
| 282 private IBinder getIBinderCallback() { |
| 283 return mIBinderCallback; |
| 284 } |
| 285 |
| 286 // Testing only related methods. |
| 287 @VisibleForTesting |
| 288 public static ChildProcessLauncherHelper createAndStartForTesting(long nativ
ePointer, |
| 289 String[] commandLine, FileDescriptorInfo[] filesToBeMapped, |
| 290 ChildProcessCreationParams creationParams, boolean sandboxed, |
| 291 boolean alwaysInForeground) { |
| 292 String processType = |
| 293 ContentSwitches.getSwitchValue(commandLine, ContentSwitches.SWIT
CH_PROCESS_TYPE); |
| 294 ChildProcessLauncherHelper launcherHelper = |
| 295 new ChildProcessLauncherHelper(nativePointer, processType); |
| 296 launcherHelper.start(ContextUtils.getApplicationContext(), commandLine,
filesToBeMapped, |
| 297 creationParams, sandboxed, alwaysInForeground); |
| 298 return launcherHelper; |
| 299 } |
| 300 |
| 301 @VisibleForTesting |
| 302 public ChildProcessConnection getChildProcessConnection() { |
| 303 return mChildProcessConnection; |
| 304 } |
133 } | 305 } |
OLD | NEW |