Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java

Issue 2795113003: Factor out inner-classes out of ChildProcessLauncher. (Closed)
Patch Set: Factor out ChildProcessConnection. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 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.ComponentName;
8 import android.content.Context; 7 import android.content.Context;
9 import android.content.pm.ApplicationInfo;
10 import android.content.pm.PackageManager;
11 import android.os.Bundle; 8 import android.os.Bundle;
12 import android.os.IBinder; 9 import android.os.IBinder;
13 import android.os.RemoteException; 10 import android.os.RemoteException;
14 import android.text.TextUtils;
15 11
16 import org.chromium.base.CpuFeatures; 12 import org.chromium.base.CpuFeatures;
17 import org.chromium.base.Log; 13 import org.chromium.base.Log;
18 import org.chromium.base.ThreadUtils; 14 import org.chromium.base.ThreadUtils;
19 import org.chromium.base.TraceEvent; 15 import org.chromium.base.TraceEvent;
20 import org.chromium.base.VisibleForTesting; 16 import org.chromium.base.VisibleForTesting;
21 import org.chromium.base.library_loader.Linker; 17 import org.chromium.base.library_loader.Linker;
22 import org.chromium.base.process_launcher.ChildProcessCreationParams; 18 import org.chromium.base.process_launcher.ChildProcessCreationParams;
23 import org.chromium.base.process_launcher.FileDescriptorInfo; 19 import org.chromium.base.process_launcher.FileDescriptorInfo;
24 import org.chromium.content.app.ChromiumLinkerParams; 20 import org.chromium.content.app.ChromiumLinkerParams;
25 import org.chromium.content.app.PrivilegedProcessService;
26 import org.chromium.content.app.SandboxedProcessService;
27 import org.chromium.content.common.ContentSwitches; 21 import org.chromium.content.common.ContentSwitches;
28 22
29 import java.util.ArrayList;
30 import java.util.LinkedList;
31 import java.util.Map; 23 import java.util.Map;
32 import java.util.Queue;
33 import java.util.concurrent.ConcurrentHashMap; 24 import java.util.concurrent.ConcurrentHashMap;
34 25
35 /** 26 /**
36 * This class provides the method to start/stop ChildProcess called by native. 27 * This class provides the method to start/stop ChildProcess called by native.
37 * 28 *
38 * Note about threading. The threading here is complicated and not well document ed. 29 * Note about threading. The threading here is complicated and not well document ed.
39 * Code can run on these threads: UI, Launcher, async thread pool, binder, and o ne-off 30 * Code can run on these threads: UI, Launcher, async thread pool, binder, and o ne-off
40 * background threads. 31 * background threads.
41 */ 32 */
42 public class ChildProcessLauncher { 33 public class ChildProcessLauncher {
43 private static final String TAG = "ChildProcLauncher"; 34 private static final String TAG = "ChildProcLauncher";
44 35
45 private static class ChildConnectionAllocator {
46 // Connections to services. Indices of the array correspond to the servi ce numbers.
47 private final ChildProcessConnection[] mChildProcessConnections;
48
49 // The list of free (not bound) service indices.
50 // SHOULD BE ACCESSED WITH mConnectionLock.
51 private final ArrayList<Integer> mFreeConnectionIndices;
52 private final Object mConnectionLock = new Object();
53
54 private final String mChildClassName;
55 private final boolean mInSandbox;
56 // Each Allocator keeps a queue for the pending spawn data. Once a conne ction is free, we
57 // dequeue the pending spawn data from the same allocator as the connect ion.
58 // SHOULD BE ACCESSED WITH mConnectionLock.
59 private final Queue<SpawnData> mPendingSpawnQueue = new LinkedList<>();
60
61 public ChildConnectionAllocator(boolean inSandbox, int numChildServices,
62 String serviceClassName) {
63 mChildProcessConnections = new ChildProcessConnectionImpl[numChildSe rvices];
64 mFreeConnectionIndices = new ArrayList<Integer>(numChildServices);
65 for (int i = 0; i < numChildServices; i++) {
66 mFreeConnectionIndices.add(i);
67 }
68 mChildClassName = serviceClassName;
69 mInSandbox = inSandbox;
70 }
71
72 // Allocate or enqueue. If there are no free slots, return null and enqu eue the spawn data.
73 public ChildProcessConnection allocate(SpawnData spawnData,
74 ChildProcessConnection.DeathCallback deathCallback,
75 Bundle childProcessCommonParameters) {
76 assert spawnData.isInSandbox() == mInSandbox;
77 synchronized (mConnectionLock) {
78 if (mFreeConnectionIndices.isEmpty()) {
79 Log.d(TAG, "Ran out of services to allocate.");
80 if (!spawnData.isForWarmUp()) {
81 mPendingSpawnQueue.add(spawnData);
82 }
83 return null;
84 }
85 int slot = mFreeConnectionIndices.remove(0);
86 assert mChildProcessConnections[slot] == null;
87 mChildProcessConnections[slot] =
88 new ChildProcessConnectionImpl(spawnData.getContext(), s lot, mInSandbox,
89 deathCallback, mChildClassName, childProcessComm onParameters,
90 spawnData.isAlwaysInForeground(), spawnData.getC reationParams());
91 Log.d(TAG, "Allocator allocated a connection, sandbox: %b, slot: %d", mInSandbox,
92 slot);
93 return mChildProcessConnections[slot];
94 }
95 }
96
97 // Also return the first SpawnData in the pending queue, if any.
98 public SpawnData free(ChildProcessConnection connection) {
99 synchronized (mConnectionLock) {
100 int slot = connection.getServiceNumber();
101 if (mChildProcessConnections[slot] != connection) {
102 int occupier = mChildProcessConnections[slot] == null
103 ? -1 : mChildProcessConnections[slot].getServiceNumb er();
104 Log.e(TAG, "Unable to find connection to free in slot: %d "
105 + "already occupied by service: %d", slot, occupier) ;
106 assert false;
107 } else {
108 mChildProcessConnections[slot] = null;
109 assert !mFreeConnectionIndices.contains(slot);
110 mFreeConnectionIndices.add(slot);
111 Log.d(TAG, "Allocator freed a connection, sandbox: %b, slot: %d", mInSandbox,
112 slot);
113 }
114 return mPendingSpawnQueue.poll();
115 }
116 }
117
118 public boolean isFreeConnectionAvailable() {
119 synchronized (mConnectionLock) {
120 return !mFreeConnectionIndices.isEmpty();
121 }
122 }
123
124 /** @return the count of connections managed by the allocator */
125 @VisibleForTesting
126 int allocatedConnectionsCountForTesting() {
127 return mChildProcessConnections.length - mFreeConnectionIndices.size ();
128 }
129
130 @VisibleForTesting
131 ChildProcessConnection[] connectionArrayForTesting() {
132 return mChildProcessConnections;
133 }
134
135 @VisibleForTesting
136 void enqueuePendingQueueForTesting(SpawnData spawnData) {
137 synchronized (mConnectionLock) {
138 mPendingSpawnQueue.add(spawnData);
139 }
140 }
141
142 @VisibleForTesting
143 int pendingSpawnsCountForTesting() {
144 synchronized (mConnectionLock) {
145 return mPendingSpawnQueue.size();
146 }
147 }
148 }
149
150 private static class SpawnData {
151 private final boolean mForWarmup; // Do not queue up if failed.
152 private final Context mContext;
153 private final String[] mCommandLine;
154 private final int mChildProcessId;
155 private final FileDescriptorInfo[] mFilesToBeMapped;
156 private final LaunchCallback mLaunchCallback;
157 private final IBinder mChildProcessCallback;
158 private final boolean mInSandbox;
159 private final boolean mAlwaysInForeground;
160 private final ChildProcessCreationParams mCreationParams;
161
162 private SpawnData(boolean forWarmUp, Context context, String[] commandLi ne,
163 int childProcessId, FileDescriptorInfo[] filesToBeMapped,
164 LaunchCallback launchCallback, IBinder childProcessCallback, boo lean inSandbox,
165 boolean alwaysInForeground, ChildProcessCreationParams creationP arams) {
166 mForWarmup = forWarmUp;
167 mContext = context;
168 mCommandLine = commandLine;
169 mChildProcessId = childProcessId;
170 mFilesToBeMapped = filesToBeMapped;
171 mLaunchCallback = launchCallback;
172 mChildProcessCallback = childProcessCallback;
173 mInSandbox = inSandbox;
174 mAlwaysInForeground = alwaysInForeground;
175 mCreationParams = creationParams;
176 }
177
178 private boolean isForWarmUp() {
179 return mForWarmup;
180 }
181 private Context getContext() {
182 return mContext;
183 }
184 private String[] getCommandLine() {
185 return mCommandLine;
186 }
187 private int getChildProcessId() {
188 return mChildProcessId;
189 }
190 private FileDescriptorInfo[] getFilesToBeMapped() {
191 return mFilesToBeMapped;
192 }
193 private LaunchCallback getLaunchCallback() {
194 return mLaunchCallback;
195 }
196 private IBinder getChildProcessCallback() {
197 return mChildProcessCallback;
198 }
199 private boolean isInSandbox() {
200 return mInSandbox;
201 }
202 private boolean isAlwaysInForeground() {
203 return mAlwaysInForeground;
204 }
205 private ChildProcessCreationParams getCreationParams() {
206 return mCreationParams;
207 }
208 }
209
210 /** 36 /**
211 * Implemented by ChildProcessLauncherHelper. 37 * Implemented by ChildProcessLauncherHelper.
212 */ 38 */
213 public interface LaunchCallback { void onChildProcessStarted(int pid); } 39 public interface LaunchCallback { void onChildProcessStarted(int pid); }
214 40
215 // Service class for child process.
216 // Map from package name to ChildConnectionAllocator.
217 private static Map<String, ChildConnectionAllocator> sSandboxedChildConnecti onAllocatorMap;
218 // As the default value it uses PrivilegedProcessService0.
219 private static ChildConnectionAllocator sPrivilegedChildConnectionAllocator;
220
221 private static final boolean SPARE_CONNECTION_ALWAYS_IN_FOREGROUND = false; 41 private static final boolean SPARE_CONNECTION_ALWAYS_IN_FOREGROUND = false;
222 42
223 private static final String NUM_SANDBOXED_SERVICES_KEY =
224 "org.chromium.content.browser.NUM_SANDBOXED_SERVICES";
225 private static final String NUM_PRIVILEGED_SERVICES_KEY =
226 "org.chromium.content.browser.NUM_PRIVILEGED_SERVICES";
227 private static final String SANDBOXED_SERVICES_NAME_KEY =
228 "org.chromium.content.browser.SANDBOXED_SERVICES_NAME";
229
230 // Used by tests to override the default sandboxed service settings.
231 private static int sSandboxedServicesCountForTesting = -1;
232 private static String sSandboxedServicesNameForTesting;
233
234 @VisibleForTesting
235 public static void setSanboxServicesSettingsForTesting(int serviceCount, Str ing serviceName) {
236 sSandboxedServicesCountForTesting = serviceCount;
237 sSandboxedServicesNameForTesting = serviceName;
238 }
239
240 static int getNumberOfServices(Context context, boolean inSandbox, String pa ckageName) {
241 int numServices = -1;
242 if (inSandbox && sSandboxedServicesCountForTesting != -1) {
243 numServices = sSandboxedServicesCountForTesting;
244 } else {
245 try {
246 PackageManager packageManager = context.getPackageManager();
247 ApplicationInfo appInfo = packageManager.getApplicationInfo(pack ageName,
248 PackageManager.GET_META_DATA);
249 if (appInfo.metaData != null) {
250 numServices = appInfo.metaData.getInt(inSandbox
251 ? NUM_SANDBOXED_SERVICES_KEY : NUM_PRIVILEGED_SERVIC ES_KEY, -1);
252 }
253 } catch (PackageManager.NameNotFoundException e) {
254 throw new RuntimeException("Could not get application info");
255 }
256 }
257 if (numServices < 0) {
258 throw new RuntimeException("Illegal meta data value for number of ch ild services");
259 }
260 return numServices;
261 }
262
263 private static String getClassNameOfService(Context context, boolean inSandb ox,
264 String packageName) {
265 if (!inSandbox) {
266 return PrivilegedProcessService.class.getName();
267 }
268
269 if (!TextUtils.isEmpty(sSandboxedServicesNameForTesting)) {
270 return sSandboxedServicesNameForTesting;
271 }
272
273 String serviceName = null;
274 try {
275 PackageManager packageManager = context.getPackageManager();
276 ApplicationInfo appInfo =
277 packageManager.getApplicationInfo(packageName, PackageManage r.GET_META_DATA);
278 if (appInfo.metaData != null) {
279 serviceName = appInfo.metaData.getString(SANDBOXED_SERVICES_NAME _KEY);
280 }
281 } catch (PackageManager.NameNotFoundException e) {
282 throw new RuntimeException("Could not get application info.");
283 }
284
285 if (serviceName != null) {
286 // Check that the service exists.
287 try {
288 PackageManager packageManager = context.getPackageManager();
289 // PackageManager#getServiceInfo() throws an exception if the se rvice does not
290 // exist.
291 packageManager.getServiceInfo(new ComponentName(packageName, ser viceName + "0"), 0);
292 return serviceName;
293 } catch (PackageManager.NameNotFoundException e) {
294 throw new RuntimeException(
295 "Illegal meta data value: the child service doesn't exis t");
296 }
297 }
298 return SandboxedProcessService.class.getName();
299 }
300
301 private static void initConnectionAllocatorsIfNecessary(
302 Context context, boolean inSandbox, String packageName) {
303 // TODO(mariakhomenko): Uses an Object to lock the access.
304 synchronized (ChildProcessLauncher.class) {
305 if (inSandbox) {
306 if (sSandboxedChildConnectionAllocatorMap == null) {
307 sSandboxedChildConnectionAllocatorMap =
308 new ConcurrentHashMap<String, ChildConnectionAllocat or>();
309 }
310 if (!sSandboxedChildConnectionAllocatorMap.containsKey(packageNa me)) {
311 Log.w(TAG, "Create a new ChildConnectionAllocator with packa ge name = %s,"
312 + " inSandbox = true",
313 packageName);
314 sSandboxedChildConnectionAllocatorMap.put(packageName,
315 new ChildConnectionAllocator(true,
316 getNumberOfServices(context, true, packageNa me),
317 getClassNameOfService(context, true, package Name)));
318 }
319 } else if (sPrivilegedChildConnectionAllocator == null) {
320 sPrivilegedChildConnectionAllocator = new ChildConnectionAllocat or(false,
321 getNumberOfServices(context, false, packageName),
322 getClassNameOfService(context, false, packageName));
323 }
324 // TODO(pkotwicz|hanxi): Figure out when old allocators should be re moved from
325 // {@code sSandboxedChildConnectionAllocatorMap}.
326 }
327 }
328
329 /**
330 * Note: please make sure that the Allocator has been initialized before cal ling this function.
331 * Otherwise, always calls {@link initConnectionAllocatorsIfNecessary} first .
332 */
333 private static ChildConnectionAllocator getConnectionAllocator(
334 String packageName, boolean inSandbox) {
335 if (!inSandbox) {
336 return sPrivilegedChildConnectionAllocator;
337 }
338 return sSandboxedChildConnectionAllocatorMap.get(packageName);
339 }
340
341 private static ChildConnectionAllocator getAllocatorForTesting(
342 Context context, String packageName, boolean inSandbox) {
343 initConnectionAllocatorsIfNecessary(context, inSandbox, packageName);
344 return getConnectionAllocator(packageName, inSandbox);
345 }
346
347 private static ChildProcessConnection allocateConnection( 43 private static ChildProcessConnection allocateConnection(
348 SpawnData spawnData, Bundle childProcessCommonParams) { 44 ChildSpawnData spawnData, Bundle childProcessCommonParams, boolean f orWarmUp) {
349 ChildProcessConnection.DeathCallback deathCallback = 45 ChildProcessConnection.DeathCallback deathCallback =
350 new ChildProcessConnection.DeathCallback() { 46 new ChildProcessConnection.DeathCallback() {
351 @Override 47 @Override
352 public void onChildProcessDied(ChildProcessConnection connec tion) { 48 public void onChildProcessDied(ChildProcessConnection connec tion) {
353 if (connection.getPid() != 0) { 49 if (connection.getPid() != 0) {
354 stop(connection.getPid()); 50 stop(connection.getPid());
355 } else { 51 } else {
356 freeConnection(connection); 52 freeConnection(connection);
357 } 53 }
358 } 54 }
359 }; 55 };
360 final ChildProcessCreationParams creationParams = spawnData.getCreationP arams(); 56 final ChildProcessCreationParams creationParams = spawnData.getCreationP arams();
361 final Context context = spawnData.getContext(); 57 final Context context = spawnData.getContext();
362 final boolean inSandbox = spawnData.isInSandbox(); 58 final boolean inSandbox = spawnData.isInSandbox();
363 String packageName = 59 String packageName =
364 creationParams != null ? creationParams.getPackageName() : conte xt.getPackageName(); 60 creationParams != null ? creationParams.getPackageName() : conte xt.getPackageName();
365 initConnectionAllocatorsIfNecessary(context, inSandbox, packageName); 61 return ChildConnectionAllocator.getAllocator(context, packageName, inSan dbox)
366 return getConnectionAllocator(packageName, inSandbox) 62 .allocate(spawnData, deathCallback, childProcessCommonParams, !f orWarmUp);
367 .allocate(spawnData, deathCallback, childProcessCommonParams);
368 } 63 }
369 64
370 private static boolean sLinkerInitialized; 65 private static boolean sLinkerInitialized;
371 private static long sLinkerLoadAddress; 66 private static long sLinkerLoadAddress;
372 67
373 private static ChromiumLinkerParams getLinkerParamsForNewConnection() { 68 private static ChromiumLinkerParams getLinkerParamsForNewConnection() {
374 if (!sLinkerInitialized) { 69 if (!sLinkerInitialized) {
375 if (Linker.isUsed()) { 70 if (Linker.isUsed()) {
376 sLinkerLoadAddress = Linker.getInstance().getBaseLoadAddress(); 71 sLinkerLoadAddress = Linker.getInstance().getBaseLoadAddress();
377 if (sLinkerLoadAddress == 0) { 72 if (sLinkerLoadAddress == 0) {
(...skipping 21 matching lines...) Expand all
399 94
400 private static Bundle createCommonParamsBundle(ChildProcessCreationParams pa rams) { 95 private static Bundle createCommonParamsBundle(ChildProcessCreationParams pa rams) {
401 Bundle commonParams = new Bundle(); 96 Bundle commonParams = new Bundle();
402 commonParams.putParcelable( 97 commonParams.putParcelable(
403 ChildProcessConstants.EXTRA_LINKER_PARAMS, getLinkerParamsForNew Connection()); 98 ChildProcessConstants.EXTRA_LINKER_PARAMS, getLinkerParamsForNew Connection());
404 final boolean bindToCallerCheck = params == null ? false : params.getBin dToCallerCheck(); 99 final boolean bindToCallerCheck = params == null ? false : params.getBin dToCallerCheck();
405 commonParams.putBoolean(ChildProcessConstants.EXTRA_BIND_TO_CALLER, bind ToCallerCheck); 100 commonParams.putBoolean(ChildProcessConstants.EXTRA_BIND_TO_CALLER, bind ToCallerCheck);
406 return commonParams; 101 return commonParams;
407 } 102 }
408 103
409 private static ChildProcessConnection allocateBoundConnection( 104 private static ChildProcessConnection allocateBoundConnection(ChildSpawnData spawnData,
410 SpawnData spawnData, ChildProcessConnection.StartCallback startCallb ack) { 105 ChildProcessConnection.StartCallback startCallback, boolean forWarmU p) {
411 final Context context = spawnData.getContext(); 106 final Context context = spawnData.getContext();
412 final boolean inSandbox = spawnData.isInSandbox(); 107 final boolean inSandbox = spawnData.isInSandbox();
413 final ChildProcessCreationParams creationParams = spawnData.getCreationP arams(); 108 final ChildProcessCreationParams creationParams = spawnData.getCreationP arams();
109
414 ChildProcessConnection connection = allocateConnection( 110 ChildProcessConnection connection = allocateConnection(
415 spawnData, createCommonParamsBundle(spawnData.getCreationParams( ))); 111 spawnData, createCommonParamsBundle(spawnData.getCreationParams( )), forWarmUp);
416 if (connection != null) { 112 if (connection != null) {
417 connection.start(startCallback); 113 connection.start(startCallback);
418 114
419 String packageName = creationParams != null ? creationParams.getPack ageName() 115 String packageName = creationParams != null ? creationParams.getPack ageName()
420 : context.getPackageName (); 116 : context.getPackageName ();
421 if (inSandbox 117 if (inSandbox
422 && !getConnectionAllocator(packageName, inSandbox) 118 && !ChildConnectionAllocator.getAllocator(context, packageNa me, inSandbox)
423 .isFreeConnectionAvailable()) { 119 .isFreeConnectionAvailable()) {
424 // Proactively releases all the moderate bindings once all the s andboxed services 120 // Proactively releases all the moderate bindings once all the s andboxed services
425 // are allocated, which will be very likely to have some of them killed by OOM 121 // are allocated, which will be very likely to have some of them killed by OOM
426 // killer. 122 // killer.
427 sBindingManager.releaseAllModerateBindings(); 123 sBindingManager.releaseAllModerateBindings();
428 } 124 }
429 } 125 }
430 return connection; 126 return connection;
431 } 127 }
432 128
433 private static final long FREE_CONNECTION_DELAY_MILLIS = 1; 129 private static final long FREE_CONNECTION_DELAY_MILLIS = 1;
434 130
435 private static void freeConnection(ChildProcessConnection connection) { 131 private static void freeConnection(ChildProcessConnection connection) {
436 synchronized (sSpareConnectionLock) { 132 synchronized (sSpareConnectionLock) {
437 if (connection.equals(sSpareSandboxedConnection)) sSpareSandboxedCon nection = null; 133 if (connection.equals(sSpareSandboxedConnection)) sSpareSandboxedCon nection = null;
438 } 134 }
439 135
440 // Freeing a service should be delayed. This is so that we avoid immedia tely reusing the 136 // Freeing a service should be delayed. This is so that we avoid immedia tely reusing the
441 // freed service (see http://crbug.com/164069): the framework might keep a service process 137 // freed service (see http://crbug.com/164069): the framework might keep a service process
442 // alive when it's been unbound for a short time. If a new connection to the same service 138 // alive when it's been unbound for a short time. If a new connection to the same service
443 // is bound at that point, the process is reused and bad things happen ( mostly static 139 // is bound at that point, the process is reused and bad things happen ( mostly static
444 // variables are set when we don't expect them to). 140 // variables are set when we don't expect them to).
445 final ChildProcessConnection conn = connection; 141 final ChildProcessConnection conn = connection;
446 ThreadUtils.postOnUiThreadDelayed(new Runnable() { 142 ThreadUtils.postOnUiThreadDelayed(new Runnable() {
447 @Override 143 @Override
448 public void run() { 144 public void run() {
449 final SpawnData pendingSpawn = freeConnectionAndDequeuePending(c onn); 145 final ChildSpawnData pendingSpawn = freeConnectionAndDequeuePend ing(conn);
450 if (pendingSpawn != null) { 146 if (pendingSpawn != null) {
451 LauncherThread.post(new Runnable() { 147 LauncherThread.post(new Runnable() {
452 @Override 148 @Override
453 public void run() { 149 public void run() {
454 startInternal(pendingSpawn.getContext(), pendingSpaw n.getCommandLine(), 150 startInternal(pendingSpawn.getContext(), pendingSpaw n.getCommandLine(),
455 pendingSpawn.getChildProcessId(), 151 pendingSpawn.getChildProcessId(),
456 pendingSpawn.getFilesToBeMapped(), 152 pendingSpawn.getFilesToBeMapped(),
457 pendingSpawn.getLaunchCallback(), 153 pendingSpawn.getLaunchCallback(),
458 pendingSpawn.getChildProcessCallback(), 154 pendingSpawn.getChildProcessCallback(),
459 pendingSpawn.isInSandbox(), pendingSpawn.isA lwaysInForeground(), 155 pendingSpawn.isInSandbox(), pendingSpawn.isA lwaysInForeground(),
460 pendingSpawn.getCreationParams()); 156 pendingSpawn.getCreationParams());
461 } 157 }
462 }); 158 });
463 } 159 }
464 } 160 }
465 }, FREE_CONNECTION_DELAY_MILLIS); 161 }, FREE_CONNECTION_DELAY_MILLIS);
466 } 162 }
467 163
468 private static SpawnData freeConnectionAndDequeuePending(ChildProcessConnect ion conn) { 164 private static ChildSpawnData freeConnectionAndDequeuePending(ChildProcessCo nnection conn) {
469 ChildConnectionAllocator allocator = getConnectionAllocator( 165 // TODO(jcivelli): it should be safe to pass a null Context here as it i s used to initialize
boliu 2017/04/12 00:20:16 assert in getAllocator that the cases where a new
Jay Civelli 2017/04/12 00:47:15 We could, but you'll get an NPE with a nice stack-
470 conn.getPackageName(), conn.isInSandbox()); 166 // the ChildConnectionAllocator object and if we are freeing a connectio n, we must have
167 // allocated one previously guaranteeing it is already initialized.
168 // When we consolidate ChildProcessLauncher and ChildProcessLauncherHelp er, we'll have a
169 // context around that we can pass in there.
170 ChildConnectionAllocator allocator = ChildConnectionAllocator.getAllocat or(
171 null /* context */, conn.getPackageName(), conn.isInSandbox());
471 assert allocator != null; 172 assert allocator != null;
472 return allocator.free(conn); 173 return allocator.free(conn);
473 } 174 }
474 175
475 // Represents an invalid process handle; same as base/process/process.h kNul lProcessHandle. 176 // Represents an invalid process handle; same as base/process/process.h kNul lProcessHandle.
476 private static final int NULL_PROCESS_HANDLE = 0; 177 private static final int NULL_PROCESS_HANDLE = 0;
477 178
478 // Map from pid to ChildService connection. 179 // Map from pid to ChildService connection.
479 private static Map<Integer, ChildProcessConnection> sServiceMap = 180 private static Map<Integer, ChildProcessConnection> sServiceMap =
480 new ConcurrentHashMap<Integer, ChildProcessConnection>(); 181 new ConcurrentHashMap<Integer, ChildProcessConnection>();
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
526 * Starts moderate binding management. 227 * Starts moderate binding management.
527 * Note: WebAPKs and non WebAPKs share the same moderate binding pool, so th e size of the 228 * Note: WebAPKs and non WebAPKs share the same moderate binding pool, so th e size of the
528 * shared moderate binding pool is always set based on the number of sandbox es processes 229 * shared moderate binding pool is always set based on the number of sandbox es processes
529 * used by Chrome. 230 * used by Chrome.
530 * @param context Android's context. 231 * @param context Android's context.
531 * @param moderateBindingTillBackgrounded true if the BindingManager should add a moderate 232 * @param moderateBindingTillBackgrounded true if the BindingManager should add a moderate
532 * binding to a render process when it is created and remove the moderate bi nding when Chrome is 233 * binding to a render process when it is created and remove the moderate bi nding when Chrome is
533 * sent to the background. 234 * sent to the background.
534 */ 235 */
535 public static void startModerateBindingManagement(Context context) { 236 public static void startModerateBindingManagement(Context context) {
536 sBindingManager.startModerateBindingManagement( 237 sBindingManager.startModerateBindingManagement(context,
537 context, getNumberOfServices(context, true, context.getPackageNa me())); 238 ChildConnectionAllocator.getNumberOfServices(
239 context, true, context.getPackageName()));
538 } 240 }
539 241
540 /** 242 /**
541 * Called when the embedding application is brought to foreground. 243 * Called when the embedding application is brought to foreground.
542 */ 244 */
543 public static void onBroughtToForeground() { 245 public static void onBroughtToForeground() {
544 sApplicationInForeground = true; 246 sApplicationInForeground = true;
545 sBindingManager.onBroughtToForeground(); 247 sBindingManager.onBroughtToForeground();
546 } 248 }
547 249
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
580 @Override 282 @Override
581 public void onChildStartFailed() { 283 public void onChildStartFailed() {
582 Log.e(TAG, "Failed to warm up the spare sandbox service"); 284 Log.e(TAG, "Failed to warm up the spare sandbox service");
583 synchronized (sSpareConnectionLock) { 285 synchronized (sSpareConnectionLock) {
584 sSpareSandboxedConnection = null; 286 sSpareSandboxedConnection = null;
585 sSpareConnectionStarting = false; 287 sSpareConnectionStarting = false;
586 sSpareConnectionLock.notify(); 288 sSpareConnectionLock.notify();
587 } 289 }
588 } 290 }
589 }; 291 };
590 SpawnData spawnData = new SpawnData(true /* forWarmUp*/, context, 292 ChildSpawnData spawnData = new ChildSpawnData(context,
591 null /* commandLine */, -1 /* child process id * /, 293 null /* commandLine */, -1 /* child process id * /,
592 null /* filesToBeMapped */, null /* launchCallba ck */, 294 null /* filesToBeMapped */, null /* launchCallba ck */,
593 null /* child process callback */, true /* inSan dbox */, 295 null /* child process callback */, true /* inSan dbox */,
594 SPARE_CONNECTION_ALWAYS_IN_FOREGROUND, params); 296 SPARE_CONNECTION_ALWAYS_IN_FOREGROUND, params);
595 sSpareSandboxedConnection = 297 sSpareSandboxedConnection = allocateBoundConnection(
596 allocateBoundConnection(spawnData, startCallback ); 298 spawnData, startCallback, true /* forWarmUp */);
597 } 299 }
598 } 300 }
599 } 301 }
600 }); 302 });
601 } 303 }
602 304
603 /** 305 /**
604 * Spawns and connects to a child process. May be called on any thread. It w ill not block, but 306 * Spawns and connects to a child process. May be called on any thread. It w ill not block, but
605 * will instead callback to {@link #nativeOnChildProcessStarted} when the co nnection is 307 * will instead callback to {@link #nativeOnChildProcessStarted} when the co nnection is
606 * established. Note this callback will not necessarily be from the same thr ead (currently it 308 * established. Note this callback will not necessarily be from the same thr ead (currently it
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
700 // so a new bound connection will be all ocated. 402 // so a new bound connection will be all ocated.
701 startInternal(context, commandLine, chil dProcessId, 403 startInternal(context, commandLine, chil dProcessId,
702 filesToBeMapped, launchCallback, 404 filesToBeMapped, launchCallback,
703 childProcessCallback, inSandbox, alwaysInForeground, 405 childProcessCallback, inSandbox, alwaysInForeground,
704 creationParams); 406 creationParams);
705 } 407 }
706 }); 408 });
707 } 409 }
708 }; 410 };
709 411
710 SpawnData spawnData = new SpawnData(false /* forWarmUp */, conte xt, commandLine, 412 ChildSpawnData spawnData = new ChildSpawnData(context, commandLi ne, childProcessId,
711 childProcessId, filesToBeMapped, launchCallback, childPr ocessCallback, 413 filesToBeMapped, launchCallback, childProcessCallback, i nSandbox,
712 inSandbox, alwaysInForeground, creationParams); 414 alwaysInForeground, creationParams);
713 allocatedConnection = allocateBoundConnection(spawnData, startCa llback); 415 allocatedConnection =
416 allocateBoundConnection(spawnData, startCallback, false /* forWarmUp */);
714 if (allocatedConnection == null) { 417 if (allocatedConnection == null) {
715 return null; 418 return null;
716 } 419 }
717 } 420 }
718 421
719 Log.d(TAG, "Setting up connection to process: slot=%d", 422 Log.d(TAG, "Setting up connection to process: slot=%d",
720 allocatedConnection.getServiceNumber()); 423 allocatedConnection.getServiceNumber());
721 triggerConnectionSetup(allocatedConnection, commandLine, childProces sId, 424 triggerConnectionSetup(allocatedConnection, commandLine, childProces sId,
722 filesToBeMapped, childProcessCallback, launchCallback); 425 filesToBeMapped, childProcessCallback, launchCallback);
723 return allocatedConnection; 426 return allocatedConnection;
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
791 FileDescriptorInfo[] filesToMap, ChildProcessCreationParams params) { 494 FileDescriptorInfo[] filesToMap, ChildProcessCreationParams params) {
792 return startInternal(context, commandLine, 0 /* childProcessId */, files ToMap, 495 return startInternal(context, commandLine, 0 /* childProcessId */, files ToMap,
793 null /* launchCallback */, null /* childProcessCallback */, true /* inSandbox */, 496 null /* launchCallback */, null /* childProcessCallback */, true /* inSandbox */,
794 false /* alwaysInForeground */, params); 497 false /* alwaysInForeground */, params);
795 } 498 }
796 499
797 @VisibleForTesting 500 @VisibleForTesting
798 static ChildProcessConnection allocateBoundConnectionForTesting(Context cont ext, 501 static ChildProcessConnection allocateBoundConnectionForTesting(Context cont ext,
799 ChildProcessCreationParams creationParams) { 502 ChildProcessCreationParams creationParams) {
800 return allocateBoundConnection( 503 return allocateBoundConnection(
801 new SpawnData(false /* forWarmUp */, context, null /* commandLin e */, 504 new ChildSpawnData(context, null /* commandLine */, 0 /* childPr ocessId */,
802 0 /* childProcessId */, null /* filesToBeMapped */, 505 null /* filesToBeMapped */, null /* LaunchCallback */,
803 null /* LaunchCallback */, null /* childProcessCallback */, 506 null /* childProcessCallback */, true /* inSandbox */,
804 true /* inSandbox */, false /* alwaysInForeground */, cr eationParams), 507 false /* alwaysInForeground */, creationParams),
805 null /* startCallback */); 508 null /* startCallback */, false /* forWarmUp */);
806 } 509 }
807 510
808 @VisibleForTesting 511 @VisibleForTesting
809 static ChildProcessConnection allocateConnectionForTesting( 512 static ChildProcessConnection allocateConnectionForTesting(
810 Context context, ChildProcessCreationParams creationParams) { 513 Context context, ChildProcessCreationParams creationParams) {
811 return allocateConnection( 514 return allocateConnection(
812 new SpawnData(false /* forWarmUp */, context, null /* commandLin e */, 515 new ChildSpawnData(context, null /* commandLine */, 0 /* childPr ocessId */,
813 0 /* childProcessId */, null /* filesToBeMapped */, 516 null /* filesToBeMapped */, null /* launchCallback */,
814 null /* launchCallback */, null /* childProcessCallback */, 517 null /* childProcessCallback */, true /* inSandbox */,
815 true /* inSandbox */, false /* alwaysInForeground */, cr eationParams), 518 false /* alwaysInForeground */, creationParams),
816 createCommonParamsBundle(creationParams)); 519 createCommonParamsBundle(creationParams), false /* forWarmUp */) ;
817 } 520 }
818 521
819 /** 522 /**
820 * Queue up a spawn requests for testing. 523 * Queue up a spawn requests for testing.
821 */ 524 */
822 @VisibleForTesting 525 @VisibleForTesting
823 static void enqueuePendingSpawnForTesting(Context context, String[] commandL ine, 526 static void enqueuePendingSpawnForTesting(Context context, String[] commandL ine,
824 ChildProcessCreationParams creationParams, boolean inSandbox) { 527 ChildProcessCreationParams creationParams, boolean inSandbox) {
825 String packageName = creationParams != null ? creationParams.getPackageN ame() 528 String packageName = creationParams != null ? creationParams.getPackageN ame()
826 : context.getPackageName(); 529 : context.getPackageName();
827 ChildConnectionAllocator allocator = 530 ChildConnectionAllocator allocator =
828 getAllocatorForTesting(context, packageName, inSandbox); 531 ChildConnectionAllocator.getAllocator(context, packageName, inSa ndbox);
829 allocator.enqueuePendingQueueForTesting(new SpawnData(false /* forWarmUp */, context, 532 allocator.enqueuePendingQueueForTesting(new ChildSpawnData(context, comm andLine,
830 commandLine, 1 /* childProcessId */, new FileDescriptorInfo[0], 533 1 /* childProcessId */, new FileDescriptorInfo[0], null /* launc hCallback */,
831 null /* launchCallback */, null /* childProcessCallback */, true /* inSandbox */, 534 null /* childProcessCallback */, true /* inSandbox */,
832 false /* alwaysInForeground */, creationParams)); 535 false /* alwaysInForeground */, creationParams));
833 } 536 }
834 537
835 /** 538 /**
836 * @return the number of sandboxed connections of given {@link packageName} managed by the 539 * @return the number of sandboxed connections of given {@link packageName} managed by the
837 * allocator. 540 * allocator.
838 */ 541 */
839 @VisibleForTesting 542 @VisibleForTesting
840 static int allocatedSandboxedConnectionsCountForTesting(Context context, Str ing packageName) { 543 static int allocatedSandboxedConnectionsCountForTesting(Context context, Str ing packageName) {
841 initConnectionAllocatorsIfNecessary(context, true, packageName); 544 return ChildConnectionAllocator.getAllocator(context, packageName, true /*isSandboxed */)
842 return sSandboxedChildConnectionAllocatorMap.get(packageName)
843 .allocatedConnectionsCountForTesting(); 545 .allocatedConnectionsCountForTesting();
844 } 546 }
845 547
846 /** 548 /**
847 * @return gets the service connection array for a specific package name. 549 * @return gets the service connection array for a specific package name.
848 */ 550 */
849 @VisibleForTesting 551 @VisibleForTesting
850 static ChildProcessConnection[] getSandboxedConnectionArrayForTesting(String packageName) { 552 static ChildProcessConnection[] getSandboxedConnectionArrayForTesting(
851 return sSandboxedChildConnectionAllocatorMap.get(packageName).connection ArrayForTesting(); 553 Context context, String packageName) {
554 return ChildConnectionAllocator.getAllocator(context, packageName, true /*isSandboxed */)
555 .connectionArrayForTesting();
852 } 556 }
853 557
854 /** @return the count of services set up and working */ 558 /** @return the count of services set up and working */
855 @VisibleForTesting 559 @VisibleForTesting
856 static int connectedServicesCountForTesting() { 560 static int connectedServicesCountForTesting() {
857 return sServiceMap.size(); 561 return sServiceMap.size();
858 } 562 }
859 563
860 /** 564 /**
861 * @param context The context. 565 * @param context The context.
862 * @param packageName The package name of the {@link ChildProcessAlocator}. 566 * @param packageName The package name of the {@link ChildProcessAlocator}.
863 * @param inSandbox Whether the connection is sandboxed. 567 * @param inSandbox Whether the connection is sandboxed.
864 * @return the count of pending spawns in the queue. 568 * @return the count of pending spawns in the queue.
865 */ 569 */
866 @VisibleForTesting 570 @VisibleForTesting
867 static int pendingSpawnsCountForTesting( 571 static int pendingSpawnsCountForTesting(
868 Context context, String packageName, boolean inSandbox) { 572 Context context, String packageName, boolean inSandbox) {
869 ChildConnectionAllocator allocator = 573 return ChildConnectionAllocator.getAllocator(context, packageName, inSan dbox)
870 getAllocatorForTesting(context, packageName, inSandbox); 574 .pendingSpawnsCountForTesting();
871 return allocator.pendingSpawnsCountForTesting();
872 } 575 }
873 576
874 /** 577 /**
875 * Kills the child process for testing. 578 * Kills the child process for testing.
876 * @return true iff the process was killed as expected 579 * @return true iff the process was killed as expected
877 */ 580 */
878 @VisibleForTesting 581 @VisibleForTesting
879 public static boolean crashProcessForTesting(int pid) { 582 public static boolean crashProcessForTesting(int pid) {
880 if (sServiceMap.get(pid) == null) return false; 583 if (sServiceMap.get(pid) == null) return false;
881 584
882 try { 585 try {
883 ((ChildProcessConnectionImpl) sServiceMap.get(pid)).crashServiceForT esting(); 586 ((ChildProcessConnectionImpl) sServiceMap.get(pid)).crashServiceForT esting();
884 } catch (RemoteException ex) { 587 } catch (RemoteException ex) {
885 return false; 588 return false;
886 } 589 }
887 590
888 return true; 591 return true;
889 } 592 }
890 } 593 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698