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 |