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

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

Issue 2792093002: Clean-up in ChildProcessLauncher. (Closed)
Patch Set: Addressed boliu@'s comment 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
« no previous file with comments | « no previous file | content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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; 7 import android.content.ComponentName;
8 import android.content.Context; 8 import android.content.Context;
9 import android.content.pm.ApplicationInfo; 9 import android.content.pm.ApplicationInfo;
10 import android.content.pm.PackageManager; 10 import android.content.pm.PackageManager;
(...skipping 25 matching lines...) Expand all
36 /** 36 /**
37 * This class provides the method to start/stop ChildProcess called by native. 37 * This class provides the method to start/stop ChildProcess called by native.
38 * 38 *
39 * Note about threading. The threading here is complicated and not well document ed. 39 * Note about threading. The threading here is complicated and not well document ed.
40 * Code can run on these threads: UI, Launcher, async thread pool, binder, and o ne-off 40 * Code can run on these threads: UI, Launcher, async thread pool, binder, and o ne-off
41 * background threads. 41 * background threads.
42 */ 42 */
43 public class ChildProcessLauncher { 43 public class ChildProcessLauncher {
44 private static final String TAG = "ChildProcLauncher"; 44 private static final String TAG = "ChildProcLauncher";
45 45
46 static final int CALLBACK_FOR_UNKNOWN_PROCESS = 0;
47 static final int CALLBACK_FOR_GPU_PROCESS = 1;
48 static final int CALLBACK_FOR_RENDERER_PROCESS = 2;
49 static final int CALLBACK_FOR_UTILITY_PROCESS = 3;
50
51 private static class ChildConnectionAllocator { 46 private static class ChildConnectionAllocator {
52 // Connections to services. Indices of the array correspond to the servi ce numbers. 47 // Connections to services. Indices of the array correspond to the servi ce numbers.
53 private final ChildProcessConnection[] mChildProcessConnections; 48 private final ChildProcessConnection[] mChildProcessConnections;
54 49
55 // The list of free (not bound) service indices. 50 // The list of free (not bound) service indices.
56 // SHOULD BE ACCESSED WITH mConnectionLock. 51 // SHOULD BE ACCESSED WITH mConnectionLock.
57 private final ArrayList<Integer> mFreeConnectionIndices; 52 private final ArrayList<Integer> mFreeConnectionIndices;
58 private final Object mConnectionLock = new Object(); 53 private final Object mConnectionLock = new Object();
59 54
60 private final String mChildClassName; 55 private final String mChildClassName;
(...skipping 10 matching lines...) Expand all
71 for (int i = 0; i < numChildServices; i++) { 66 for (int i = 0; i < numChildServices; i++) {
72 mFreeConnectionIndices.add(i); 67 mFreeConnectionIndices.add(i);
73 } 68 }
74 mChildClassName = serviceClassName; 69 mChildClassName = serviceClassName;
75 mInSandbox = inSandbox; 70 mInSandbox = inSandbox;
76 } 71 }
77 72
78 // Allocate or enqueue. If there are no free slots, return null and enqu eue the spawn data. 73 // Allocate or enqueue. If there are no free slots, return null and enqu eue the spawn data.
79 public ChildProcessConnection allocate(SpawnData spawnData, 74 public ChildProcessConnection allocate(SpawnData spawnData,
80 ChildProcessConnection.DeathCallback deathCallback, 75 ChildProcessConnection.DeathCallback deathCallback,
81 Bundle childProcessCommonParameters, boolean alwaysInForeground) { 76 Bundle childProcessCommonParameters) {
82 assert spawnData.inSandbox() == mInSandbox; 77 assert spawnData.isInSandbox() == mInSandbox;
83 synchronized (mConnectionLock) { 78 synchronized (mConnectionLock) {
84 if (mFreeConnectionIndices.isEmpty()) { 79 if (mFreeConnectionIndices.isEmpty()) {
85 Log.d(TAG, "Ran out of services to allocate."); 80 Log.d(TAG, "Ran out of services to allocate.");
86 if (!spawnData.forWarmUp()) { 81 if (!spawnData.isForWarmUp()) {
87 mPendingSpawnQueue.add(spawnData); 82 mPendingSpawnQueue.add(spawnData);
88 } 83 }
89 return null; 84 return null;
90 } 85 }
91 int slot = mFreeConnectionIndices.remove(0); 86 int slot = mFreeConnectionIndices.remove(0);
92 assert mChildProcessConnections[slot] == null; 87 assert mChildProcessConnections[slot] == null;
93 mChildProcessConnections[slot] = 88 mChildProcessConnections[slot] =
94 new ChildProcessConnectionImpl(spawnData.context(), slot , mInSandbox, 89 new ChildProcessConnectionImpl(spawnData.getContext(), s lot, mInSandbox,
95 deathCallback, mChildClassName, childProcessComm onParameters, 90 deathCallback, mChildClassName, childProcessComm onParameters,
96 alwaysInForeground, spawnData.getCreationParams( )); 91 spawnData.isAlwaysInForeground(), spawnData.getC reationParams());
97 Log.d(TAG, "Allocator allocated a connection, sandbox: %b, slot: %d", mInSandbox, 92 Log.d(TAG, "Allocator allocated a connection, sandbox: %b, slot: %d", mInSandbox,
98 slot); 93 slot);
99 return mChildProcessConnections[slot]; 94 return mChildProcessConnections[slot];
100 } 95 }
101 } 96 }
102 97
103 // Also return the first SpawnData in the pending queue, if any. 98 // Also return the first SpawnData in the pending queue, if any.
104 public SpawnData free(ChildProcessConnection connection) { 99 public SpawnData free(ChildProcessConnection connection) {
105 synchronized (mConnectionLock) { 100 synchronized (mConnectionLock) {
106 int slot = connection.getServiceNumber(); 101 int slot = connection.getServiceNumber();
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 } 148 }
154 } 149 }
155 150
156 private static class SpawnData { 151 private static class SpawnData {
157 private final boolean mForWarmup; // Do not queue up if failed. 152 private final boolean mForWarmup; // Do not queue up if failed.
158 private final Context mContext; 153 private final Context mContext;
159 private final String[] mCommandLine; 154 private final String[] mCommandLine;
160 private final int mChildProcessId; 155 private final int mChildProcessId;
161 private final FileDescriptorInfo[] mFilesToBeMapped; 156 private final FileDescriptorInfo[] mFilesToBeMapped;
162 private final LaunchCallback mLaunchCallback; 157 private final LaunchCallback mLaunchCallback;
163 private final int mCallbackType; 158 private final IBinder mChildProcessCallback;
164 private final boolean mInSandbox; 159 private final boolean mInSandbox;
160 private final boolean mAlwaysInForeground;
165 private final ChildProcessCreationParams mCreationParams; 161 private final ChildProcessCreationParams mCreationParams;
166 162
167 private SpawnData(boolean forWarmUp, Context context, String[] commandLi ne, 163 private SpawnData(boolean forWarmUp, Context context, String[] commandLi ne,
168 int childProcessId, FileDescriptorInfo[] filesToBeMapped, 164 int childProcessId, FileDescriptorInfo[] filesToBeMapped,
169 LaunchCallback launchCallback, int callbackType, boolean inSandb ox, 165 LaunchCallback launchCallback, IBinder childProcessCallback, boo lean inSandbox,
170 ChildProcessCreationParams creationParams) { 166 boolean alwaysInForeground, ChildProcessCreationParams creationP arams) {
171 mForWarmup = forWarmUp; 167 mForWarmup = forWarmUp;
172 mContext = context; 168 mContext = context;
173 mCommandLine = commandLine; 169 mCommandLine = commandLine;
174 mChildProcessId = childProcessId; 170 mChildProcessId = childProcessId;
175 mFilesToBeMapped = filesToBeMapped; 171 mFilesToBeMapped = filesToBeMapped;
176 mLaunchCallback = launchCallback; 172 mLaunchCallback = launchCallback;
177 mCallbackType = callbackType; 173 mChildProcessCallback = childProcessCallback;
178 mInSandbox = inSandbox; 174 mInSandbox = inSandbox;
175 mAlwaysInForeground = alwaysInForeground;
179 mCreationParams = creationParams; 176 mCreationParams = creationParams;
180 } 177 }
181 178
182 private boolean forWarmUp() { 179 private boolean isForWarmUp() {
183 return mForWarmup; 180 return mForWarmup;
184 } 181 }
185 182 private Context getContext() {
186 private Context context() {
187 return mContext; 183 return mContext;
188 } 184 }
189 private String[] commandLine() { 185 private String[] getCommandLine() {
190 return mCommandLine; 186 return mCommandLine;
191 } 187 }
192 private int childProcessId() { 188 private int getChildProcessId() {
193 return mChildProcessId; 189 return mChildProcessId;
194 } 190 }
195 private FileDescriptorInfo[] filesToBeMapped() { 191 private FileDescriptorInfo[] getFilesToBeMapped() {
196 return mFilesToBeMapped; 192 return mFilesToBeMapped;
197 } 193 }
198 private LaunchCallback launchCallback() { 194 private LaunchCallback getLaunchCallback() {
199 return mLaunchCallback; 195 return mLaunchCallback;
200 } 196 }
201 private int callbackType() { 197 private IBinder getChildProcessCallback() {
202 return mCallbackType; 198 return mChildProcessCallback;
203 } 199 }
204 private boolean inSandbox() { 200 private boolean isInSandbox() {
205 return mInSandbox; 201 return mInSandbox;
206 } 202 }
203 private boolean isAlwaysInForeground() {
204 return mAlwaysInForeground;
205 }
207 private ChildProcessCreationParams getCreationParams() { 206 private ChildProcessCreationParams getCreationParams() {
208 return mCreationParams; 207 return mCreationParams;
209 } 208 }
210 } 209 }
211 210
212 /** 211 /**
213 * Implemented by ChildProcessLauncherHelper. 212 * Implemented by ChildProcessLauncherHelper.
214 */ 213 */
215 public interface LaunchCallback { void onChildProcessStarted(int pid); } 214 public interface LaunchCallback { void onChildProcessStarted(int pid); }
216 215
217 // Service class for child process. 216 // Service class for child process.
218 // Map from package name to ChildConnectionAllocator. 217 // Map from package name to ChildConnectionAllocator.
219 private static Map<String, ChildConnectionAllocator> sSandboxedChildConnecti onAllocatorMap; 218 private static Map<String, ChildConnectionAllocator> sSandboxedChildConnecti onAllocatorMap;
220 // As the default value it uses PrivilegedProcessService0. 219 // As the default value it uses PrivilegedProcessService0.
221 private static ChildConnectionAllocator sPrivilegedChildConnectionAllocator; 220 private static ChildConnectionAllocator sPrivilegedChildConnectionAllocator;
222 221
222 private static final boolean SPARE_CONNECTION_ALWAYS_IN_FOREGROUND = false;
223
223 private static final String NUM_SANDBOXED_SERVICES_KEY = 224 private static final String NUM_SANDBOXED_SERVICES_KEY =
224 "org.chromium.content.browser.NUM_SANDBOXED_SERVICES"; 225 "org.chromium.content.browser.NUM_SANDBOXED_SERVICES";
225 private static final String NUM_PRIVILEGED_SERVICES_KEY = 226 private static final String NUM_PRIVILEGED_SERVICES_KEY =
226 "org.chromium.content.browser.NUM_PRIVILEGED_SERVICES"; 227 "org.chromium.content.browser.NUM_PRIVILEGED_SERVICES";
227 private static final String SANDBOXED_SERVICES_NAME_KEY = 228 private static final String SANDBOXED_SERVICES_NAME_KEY =
228 "org.chromium.content.browser.SANDBOXED_SERVICES_NAME"; 229 "org.chromium.content.browser.SANDBOXED_SERVICES_NAME";
229 // Overrides the number of available sandboxed services. 230 // Overrides the number of available sandboxed services.
230 @VisibleForTesting 231 @VisibleForTesting
231 public static final String SWITCH_NUM_SANDBOXED_SERVICES_FOR_TESTING = "num- sandboxed-services"; 232 public static final String SWITCH_NUM_SANDBOXED_SERVICES_FOR_TESTING = "num- sandboxed-services";
232 public static final String SWITCH_SANDBOXED_SERVICES_NAME_FOR_TESTING = 233 public static final String SWITCH_SANDBOXED_SERVICES_NAME_FOR_TESTING =
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 return sSandboxedChildConnectionAllocatorMap.get(packageName); 345 return sSandboxedChildConnectionAllocatorMap.get(packageName);
345 } 346 }
346 347
347 private static ChildConnectionAllocator getAllocatorForTesting( 348 private static ChildConnectionAllocator getAllocatorForTesting(
348 Context context, String packageName, boolean inSandbox) { 349 Context context, String packageName, boolean inSandbox) {
349 initConnectionAllocatorsIfNecessary(context, inSandbox, packageName); 350 initConnectionAllocatorsIfNecessary(context, inSandbox, packageName);
350 return getConnectionAllocator(packageName, inSandbox); 351 return getConnectionAllocator(packageName, inSandbox);
351 } 352 }
352 353
353 private static ChildProcessConnection allocateConnection( 354 private static ChildProcessConnection allocateConnection(
354 SpawnData spawnData, Bundle childProcessCommonParams, boolean always InForeground) { 355 SpawnData spawnData, Bundle childProcessCommonParams) {
355 ChildProcessConnection.DeathCallback deathCallback = 356 ChildProcessConnection.DeathCallback deathCallback =
356 new ChildProcessConnection.DeathCallback() { 357 new ChildProcessConnection.DeathCallback() {
357 @Override 358 @Override
358 public void onChildProcessDied(ChildProcessConnection connec tion) { 359 public void onChildProcessDied(ChildProcessConnection connec tion) {
359 if (connection.getPid() != 0) { 360 if (connection.getPid() != 0) {
360 stop(connection.getPid()); 361 stop(connection.getPid());
361 } else { 362 } else {
362 freeConnection(connection); 363 freeConnection(connection);
363 } 364 }
364 } 365 }
365 }; 366 };
366 final ChildProcessCreationParams creationParams = spawnData.getCreationP arams(); 367 final ChildProcessCreationParams creationParams = spawnData.getCreationP arams();
367 final Context context = spawnData.context(); 368 final Context context = spawnData.getContext();
368 final boolean inSandbox = spawnData.inSandbox(); 369 final boolean inSandbox = spawnData.isInSandbox();
369 String packageName = 370 String packageName =
370 creationParams != null ? creationParams.getPackageName() : conte xt.getPackageName(); 371 creationParams != null ? creationParams.getPackageName() : conte xt.getPackageName();
371 initConnectionAllocatorsIfNecessary(context, inSandbox, packageName); 372 initConnectionAllocatorsIfNecessary(context, inSandbox, packageName);
372 return getConnectionAllocator(packageName, inSandbox) 373 return getConnectionAllocator(packageName, inSandbox)
373 .allocate(spawnData, deathCallback, childProcessCommonParams, al waysInForeground); 374 .allocate(spawnData, deathCallback, childProcessCommonParams);
374 } 375 }
375 376
376 private static boolean sLinkerInitialized; 377 private static boolean sLinkerInitialized;
377 private static long sLinkerLoadAddress; 378 private static long sLinkerLoadAddress;
378 379
379 private static ChromiumLinkerParams getLinkerParamsForNewConnection() { 380 private static ChromiumLinkerParams getLinkerParamsForNewConnection() {
380 if (!sLinkerInitialized) { 381 if (!sLinkerInitialized) {
381 if (Linker.isUsed()) { 382 if (Linker.isUsed()) {
382 sLinkerLoadAddress = Linker.getInstance().getBaseLoadAddress(); 383 sLinkerLoadAddress = Linker.getInstance().getBaseLoadAddress();
383 if (sLinkerLoadAddress == 0) { 384 if (sLinkerLoadAddress == 0) {
(...skipping 12 matching lines...) Expand all
396 return new ChromiumLinkerParams(sLinkerLoadAddress, 397 return new ChromiumLinkerParams(sLinkerLoadAddress,
397 waitForSharedRelros, 398 waitForSharedRelros,
398 linker.getTestRunnerClassNameForTest ing(), 399 linker.getTestRunnerClassNameForTest ing(),
399 linker.getImplementationForTesting() ); 400 linker.getImplementationForTesting() );
400 } else { 401 } else {
401 return new ChromiumLinkerParams(sLinkerLoadAddress, 402 return new ChromiumLinkerParams(sLinkerLoadAddress,
402 waitForSharedRelros); 403 waitForSharedRelros);
403 } 404 }
404 } 405 }
405 406
406 private static ChildProcessConnection allocateBoundConnection(SpawnData spaw nData, 407 private static ChildProcessConnection allocateBoundConnection(
407 boolean alwaysInForeground, ChildProcessConnection.StartCallback sta rtCallback) { 408 SpawnData spawnData, ChildProcessConnection.StartCallback startCallb ack) {
408 final Context context = spawnData.context(); 409 final Context context = spawnData.getContext();
409 final boolean inSandbox = spawnData.inSandbox(); 410 final boolean inSandbox = spawnData.isInSandbox();
410 final ChildProcessCreationParams creationParams = spawnData.getCreationP arams(); 411 final ChildProcessCreationParams creationParams = spawnData.getCreationP arams();
411 Bundle commonParams = new Bundle(); 412 Bundle commonParams = new Bundle();
412 commonParams.putParcelable( 413 commonParams.putParcelable(
413 ChildProcessConstants.EXTRA_LINKER_PARAMS, getLinkerParamsForNew Connection()); 414 ChildProcessConstants.EXTRA_LINKER_PARAMS, getLinkerParamsForNew Connection());
414 ChildProcessConnection connection = 415 ChildProcessConnection connection = allocateConnection(spawnData, common Params);
415 allocateConnection(spawnData, commonParams, alwaysInForeground);
416 if (connection != null) { 416 if (connection != null) {
417 connection.start(startCallback); 417 connection.start(startCallback);
418 418
419 String packageName = creationParams != null ? creationParams.getPack ageName() 419 String packageName = creationParams != null ? creationParams.getPack ageName()
420 : context.getPackageName (); 420 : context.getPackageName ();
421 if (inSandbox 421 if (inSandbox
422 && !getConnectionAllocator(packageName, inSandbox) 422 && !getConnectionAllocator(packageName, inSandbox)
423 .isFreeConnectionAvailable()) { 423 .isFreeConnectionAvailable()) {
424 // Proactively releases all the moderate bindings once all the s andboxed services 424 // 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 425 // are allocated, which will be very likely to have some of them killed by OOM
(...skipping 18 matching lines...) Expand all
444 // variables are set when we don't expect them to). 444 // variables are set when we don't expect them to).
445 final ChildProcessConnection conn = connection; 445 final ChildProcessConnection conn = connection;
446 ThreadUtils.postOnUiThreadDelayed(new Runnable() { 446 ThreadUtils.postOnUiThreadDelayed(new Runnable() {
447 @Override 447 @Override
448 public void run() { 448 public void run() {
449 final SpawnData pendingSpawn = freeConnectionAndDequeuePending(c onn); 449 final SpawnData pendingSpawn = freeConnectionAndDequeuePending(c onn);
450 if (pendingSpawn != null) { 450 if (pendingSpawn != null) {
451 LauncherThread.post(new Runnable() { 451 LauncherThread.post(new Runnable() {
452 @Override 452 @Override
453 public void run() { 453 public void run() {
454 startInternal(pendingSpawn.context(), pendingSpawn.c ommandLine(), 454 startInternal(pendingSpawn.getContext(), pendingSpaw n.getCommandLine(),
455 pendingSpawn.childProcessId(), pendingSpawn. filesToBeMapped(), 455 pendingSpawn.getChildProcessId(),
456 pendingSpawn.launchCallback(), pendingSpawn. callbackType(), 456 pendingSpawn.getFilesToBeMapped(),
457 pendingSpawn.inSandbox(), pendingSpawn.getCr eationParams()); 457 pendingSpawn.getLaunchCallback(),
458 pendingSpawn.getChildProcessCallback(),
459 pendingSpawn.isInSandbox(), pendingSpawn.isA lwaysInForeground(),
460 pendingSpawn.getCreationParams());
458 } 461 }
459 }); 462 });
460 } 463 }
461 } 464 }
462 }, FREE_CONNECTION_DELAY_MILLIS); 465 }, FREE_CONNECTION_DELAY_MILLIS);
463 } 466 }
464 467
465 private static SpawnData freeConnectionAndDequeuePending(ChildProcessConnect ion conn) { 468 private static SpawnData freeConnectionAndDequeuePending(ChildProcessConnect ion conn) {
466 ChildConnectionAllocator allocator = getConnectionAllocator( 469 ChildConnectionAllocator allocator = getConnectionAllocator(
467 conn.getPackageName(), conn.isInSandbox()); 470 conn.getPackageName(), conn.isInSandbox());
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
578 synchronized (sSpareConnectionLock) { 581 synchronized (sSpareConnectionLock) {
579 sSpareSandboxedConnection = null; 582 sSpareSandboxedConnection = null;
580 sSpareConnectionStarting = false; 583 sSpareConnectionStarting = false;
581 sSpareConnectionLock.notify(); 584 sSpareConnectionLock.notify();
582 } 585 }
583 } 586 }
584 }; 587 };
585 SpawnData spawnData = new SpawnData(true /* forWarmUp*/, context , 588 SpawnData spawnData = new SpawnData(true /* forWarmUp*/, context ,
586 null /* commandLine */, -1 /* child process id */, 589 null /* commandLine */, -1 /* child process id */,
587 null /* filesToBeMapped */, null /* launchCallback */, 590 null /* filesToBeMapped */, null /* launchCallback */,
588 CALLBACK_FOR_RENDERER_PROCESS, true /* inSandbox */, par ams); 591 null /* child process callback */, true /* inSandbox */,
589 sSpareSandboxedConnection = allocateBoundConnection( 592 SPARE_CONNECTION_ALWAYS_IN_FOREGROUND, params);
590 spawnData, false /* alwaysInForeground */, startCallback ); 593 sSpareSandboxedConnection = allocateBoundConnection(spawnData, s tartCallback);
591 } 594 }
592 } 595 }
593 } 596 }
594 597
595 /** 598 /**
596 * Spawns and connects to a child process. May be called on any thread. It w ill not block, but 599 * Spawns and connects to a child process. May be called on any thread. It w ill not block, but
597 * will instead callback to {@link #nativeOnChildProcessStarted} when the co nnection is 600 * will instead callback to {@link #nativeOnChildProcessStarted} when the co nnection is
598 * established. Note this callback will not necessarily be from the same thr ead (currently it 601 * established. Note this callback will not necessarily be from the same thr ead (currently it
599 * always comes from the main thread). 602 * always comes from the main thread).
600 * 603 *
601 * @param context Context used to obtain the application context. 604 * @param context Context used to obtain the application context.
602 * @param paramId Key used to retrieve ChildProcessCreationParams. 605 * @param paramId Key used to retrieve ChildProcessCreationParams.
603 * @param commandLine The child process command line argv. 606 * @param commandLine The child process command line argv.
604 * @param filesToBeMapped File IDs, FDs, offsets, and lengths to pass throug h. 607 * @param filesToBeMapped File IDs, FDs, offsets, and lengths to pass throug h.
605 */ 608 */
606 // TODO(boliu): All tests should use this over startForTesting. 609 // TODO(boliu): All tests should use this over startForTesting.
607 static void start(Context context, int paramId, final String[] commandLine, int childProcessId, 610 static void start(Context context, int paramId, final String[] commandLine, int childProcessId,
608 FileDescriptorInfo[] filesToBeMapped, LaunchCallback launchCallback) { 611 FileDescriptorInfo[] filesToBeMapped, LaunchCallback launchCallback) {
609 int callbackType = CALLBACK_FOR_UNKNOWN_PROCESS; 612 IBinder childProcessCallback = null;
610 boolean inSandbox = true; 613 boolean inSandbox = true;
614 boolean alwaysInForeground = false;
611 String processType = 615 String processType =
612 ContentSwitches.getSwitchValue(commandLine, ContentSwitches.SWIT CH_PROCESS_TYPE); 616 ContentSwitches.getSwitchValue(commandLine, ContentSwitches.SWIT CH_PROCESS_TYPE);
613 ChildProcessCreationParams params = ChildProcessCreationParams.get(param Id); 617 ChildProcessCreationParams params = ChildProcessCreationParams.get(param Id);
614 if (paramId != ChildProcessCreationParams.DEFAULT_ID && params == null) { 618 if (paramId != ChildProcessCreationParams.DEFAULT_ID && params == null) {
615 throw new RuntimeException("CreationParams id " + paramId + " not fo und"); 619 throw new RuntimeException("CreationParams id " + paramId + " not fo und");
616 } 620 }
617 if (ContentSwitches.SWITCH_RENDERER_PROCESS.equals(processType)) { 621 if (!ContentSwitches.SWITCH_RENDERER_PROCESS.equals(processType)) {
618 callbackType = CALLBACK_FOR_RENDERER_PROCESS;
619 } else {
620 if (params != null && !params.getPackageName().equals(context.getPac kageName())) { 622 if (params != null && !params.getPackageName().equals(context.getPac kageName())) {
621 // WebViews and WebAPKs have renderer processes running in their applications. 623 // WebViews and WebAPKs have renderer processes running in their applications.
622 // When launching these renderer processes, {@link ChildProcessC onnectionImpl} 624 // When launching these renderer processes, {@link ChildProcessC onnectionImpl}
623 // requires the package name of the application which holds the renderer process. 625 // requires the package name of the application which holds the renderer process.
624 // Therefore, the package name in ChildProcessCreationParams cou ld be the package 626 // Therefore, the package name in ChildProcessCreationParams cou ld be the package
625 // name of WebViews, WebAPKs, or Chrome, depending on the host a pplication. 627 // name of WebViews, WebAPKs, or Chrome, depending on the host a pplication.
626 // Except renderer process, all other child processes should use Chrome's package 628 // Except renderer process, all other child processes should use Chrome's package
627 // name. In WebAPK, ChildProcessCreationParams are initialized w ith WebAPK's 629 // name. In WebAPK, ChildProcessCreationParams are initialized w ith WebAPK's
628 // package name. Make a copy of the WebAPK's params, but replace the package with 630 // package name. Make a copy of the WebAPK's params, but replace the package with
629 // Chrome's package to use when initializing a non-renderer proc esses. 631 // Chrome's package to use when initializing a non-renderer proc esses.
630 // TODO(boliu): Should fold into |paramId|. Investigate why this is needed. 632 // TODO(boliu): Should fold into |paramId|. Investigate why this is needed.
631 params = new ChildProcessCreationParams(context.getPackageName() , 633 params = new ChildProcessCreationParams(context.getPackageName() ,
632 params.getIsExternalService(), params.getLibraryProcessT ype()); 634 params.getIsExternalService(), params.getLibraryProcessT ype());
633 } 635 }
634 if (ContentSwitches.SWITCH_GPU_PROCESS.equals(processType)) { 636 if (ContentSwitches.SWITCH_GPU_PROCESS.equals(processType)) {
635 callbackType = CALLBACK_FOR_GPU_PROCESS; 637 childProcessCallback = new GpuProcessCallback();
636 inSandbox = false; 638 inSandbox = false;
637 } else if (ContentSwitches.SWITCH_UTILITY_PROCESS.equals(processType )) { 639 alwaysInForeground = true;
638 // We only support sandboxed right now.
639 callbackType = CALLBACK_FOR_UTILITY_PROCESS;
640 } else { 640 } else {
641 assert false; 641 // We only support sandboxed utility processes now.
642 assert ContentSwitches.SWITCH_UTILITY_PROCESS.equals(processType );
642 } 643 }
643 } 644 }
644 645
645 startInternal(context, commandLine, childProcessId, filesToBeMapped, lau nchCallback, 646 startInternal(context, commandLine, childProcessId, filesToBeMapped, lau nchCallback,
646 callbackType, inSandbox, params); 647 childProcessCallback, inSandbox, alwaysInForeground, params);
647 } 648 }
648 649
649 private static ChildProcessConnection startInternal(final Context context, 650 private static ChildProcessConnection startInternal(final Context context,
650 final String[] commandLine, final int childProcessId, 651 final String[] commandLine, final int childProcessId,
651 final FileDescriptorInfo[] filesToBeMapped, final LaunchCallback lau nchCallback, 652 final FileDescriptorInfo[] filesToBeMapped, final LaunchCallback lau nchCallback,
652 final int callbackType, final boolean inSandbox, 653 final IBinder childProcessCallback, final boolean inSandbox,
653 final ChildProcessCreationParams creationParams) { 654 final boolean alwaysInForeground, final ChildProcessCreationParams c reationParams) {
654 try { 655 try {
655 TraceEvent.begin("ChildProcessLauncher.startInternal"); 656 TraceEvent.begin("ChildProcessLauncher.startInternal");
656 657
657 ChildProcessConnection allocatedConnection = null; 658 ChildProcessConnection allocatedConnection = null;
658 String packageName = creationParams != null ? creationParams.getPack ageName() 659 String packageName = creationParams != null ? creationParams.getPack ageName()
659 : context.getPackageName(); 660 : context.getPackageName();
660 synchronized (sSpareConnectionLock) { 661 synchronized (sSpareConnectionLock) {
661 if (inSandbox && sSpareSandboxedConnection != null 662 if (inSandbox && sSpareSandboxedConnection != null
663 && SPARE_CONNECTION_ALWAYS_IN_FOREGROUND == alwaysInFore ground
662 && sSpareSandboxedConnection.getPackageName().equals(pac kageName) 664 && sSpareSandboxedConnection.getPackageName().equals(pac kageName)
663 // Object identity check for getDefault should be enough . The default is 665 // Object identity check for getDefault should be enough . The default is
664 // not supposed to change once set. 666 // not supposed to change once set.
665 && creationParams == ChildProcessCreationParams.getDefau lt()) { 667 && creationParams == ChildProcessCreationParams.getDefau lt()) {
666 while (sSpareConnectionStarting) { 668 while (sSpareConnectionStarting) {
667 try { 669 try {
668 sSpareConnectionLock.wait(); 670 sSpareConnectionLock.wait();
669 } catch (InterruptedException ex) { 671 } catch (InterruptedException ex) {
670 } 672 }
671 } 673 }
672 allocatedConnection = sSpareSandboxedConnection; 674 allocatedConnection = sSpareSandboxedConnection;
673 sSpareSandboxedConnection = null; 675 sSpareSandboxedConnection = null;
674 } 676 }
675 } 677 }
676 if (allocatedConnection == null) { 678 if (allocatedConnection == null) {
677 boolean alwaysInForeground = false;
678 if (callbackType == CALLBACK_FOR_GPU_PROCESS) alwaysInForeground = true;
679 ChildProcessConnection.StartCallback startCallback = 679 ChildProcessConnection.StartCallback startCallback =
680 new ChildProcessConnection.StartCallback() { 680 new ChildProcessConnection.StartCallback() {
681 @Override 681 @Override
682 public void onChildStarted() {} 682 public void onChildStarted() {}
683 683
684 @Override 684 @Override
685 public void onChildStartFailed() { 685 public void onChildStartFailed() {
686 Log.e(TAG, "ChildProcessConnection.start failed, trying again"); 686 Log.e(TAG, "ChildProcessConnection.start failed, trying again");
687 LauncherThread.post(new Runnable() { 687 LauncherThread.post(new Runnable() {
688 @Override 688 @Override
689 public void run() { 689 public void run() {
690 // The child process may already be boun d to another client 690 // The child process may already be boun d to another client
691 // (this can happen if multi-process Web View is used in more 691 // (this can happen if multi-process Web View is used in more
692 // than one process), so try starting th e process again. 692 // than one process), so try starting th e process again.
693 // This connection that failed to start has not been freed, 693 // This connection that failed to start has not been freed,
694 // so a new bound connection will be all ocated. 694 // so a new bound connection will be all ocated.
695 startInternal(context, commandLine, chil dProcessId, 695 startInternal(context, commandLine, chil dProcessId,
696 filesToBeMapped, launchCallback, callbackType, 696 filesToBeMapped, launchCallback,
697 inSandbox, creationParams); 697 childProcessCallback, inSandbox, alwaysInForeground,
698 creationParams);
698 } 699 }
699 }); 700 });
700 } 701 }
701 }; 702 };
702 703
703 SpawnData spawnData = new SpawnData(false /* forWarmUp */, conte xt, commandLine, 704 SpawnData spawnData = new SpawnData(false /* forWarmUp */, conte xt, commandLine,
704 childProcessId, filesToBeMapped, launchCallback, callbac kType, inSandbox, 705 childProcessId, filesToBeMapped, launchCallback, childPr ocessCallback,
705 creationParams); 706 inSandbox, alwaysInForeground, creationParams);
706 allocatedConnection = 707 allocatedConnection = allocateBoundConnection(spawnData, startCa llback);
707 allocateBoundConnection(spawnData, alwaysInForeground, s tartCallback);
708 if (allocatedConnection == null) { 708 if (allocatedConnection == null) {
709 return null; 709 return null;
710 } 710 }
711 } 711 }
712 712
713 Log.d(TAG, "Setting up connection to process: slot=%d", 713 Log.d(TAG, "Setting up connection to process: slot=%d",
714 allocatedConnection.getServiceNumber()); 714 allocatedConnection.getServiceNumber());
715 triggerConnectionSetup(allocatedConnection, commandLine, childProces sId, 715 triggerConnectionSetup(allocatedConnection, commandLine, childProces sId,
716 filesToBeMapped, callbackType, launchCallback); 716 filesToBeMapped, childProcessCallback, launchCallback);
717 return allocatedConnection; 717 return allocatedConnection;
718 } finally { 718 } finally {
719 TraceEvent.end("ChildProcessLauncher.startInternal"); 719 TraceEvent.end("ChildProcessLauncher.startInternal");
720 } 720 }
721 } 721 }
722 722
723 /** 723 /**
724 * Create the common bundle to be passed to child processes. 724 * Create the common bundle to be passed to child processes.
725 * @param context Application context. 725 * @param context Application context.
726 * @param commandLine Command line params to be passed to the service. 726 * @param commandLine Command line params to be passed to the service.
727 * @param linkerParams Linker params to start the service. 727 * @param linkerParams Linker params to start the service.
728 */ 728 */
729 protected static Bundle createsServiceBundle( 729 protected static Bundle createsServiceBundle(
730 String[] commandLine, FileDescriptorInfo[] filesToBeMapped) { 730 String[] commandLine, FileDescriptorInfo[] filesToBeMapped) {
731 Bundle bundle = new Bundle(); 731 Bundle bundle = new Bundle();
732 bundle.putStringArray(ChildProcessConstants.EXTRA_COMMAND_LINE, commandL ine); 732 bundle.putStringArray(ChildProcessConstants.EXTRA_COMMAND_LINE, commandL ine);
733 bundle.putParcelableArray(ChildProcessConstants.EXTRA_FILES, filesToBeMa pped); 733 bundle.putParcelableArray(ChildProcessConstants.EXTRA_FILES, filesToBeMa pped);
734 bundle.putInt(ChildProcessConstants.EXTRA_CPU_COUNT, CpuFeatures.getCoun t()); 734 bundle.putInt(ChildProcessConstants.EXTRA_CPU_COUNT, CpuFeatures.getCoun t());
735 bundle.putLong(ChildProcessConstants.EXTRA_CPU_FEATURES, CpuFeatures.get Mask()); 735 bundle.putLong(ChildProcessConstants.EXTRA_CPU_FEATURES, CpuFeatures.get Mask());
736 bundle.putBundle(Linker.EXTRA_LINKER_SHARED_RELROS, Linker.getInstance() .getSharedRelros()); 736 bundle.putBundle(Linker.EXTRA_LINKER_SHARED_RELROS, Linker.getInstance() .getSharedRelros());
737 return bundle; 737 return bundle;
738 } 738 }
739 739
740 @VisibleForTesting 740 @VisibleForTesting
741 static void triggerConnectionSetup(final ChildProcessConnection connection, 741 static void triggerConnectionSetup(final ChildProcessConnection connection,
742 String[] commandLine, int childProcessId, FileDescriptorInfo[] files ToBeMapped, 742 String[] commandLine, int childProcessId, FileDescriptorInfo[] files ToBeMapped,
743 final int callbackType, final LaunchCallback launchCallback) { 743 final IBinder childProcessCallback, final LaunchCallback launchCallb ack) {
744 ChildProcessConnection.ConnectionCallback connectionCallback = 744 ChildProcessConnection.ConnectionCallback connectionCallback =
745 new ChildProcessConnection.ConnectionCallback() { 745 new ChildProcessConnection.ConnectionCallback() {
746 @Override 746 @Override
747 public void onConnected(int pid) { 747 public void onConnected(int pid) {
748 Log.d(TAG, "on connect callback, pid=%d callbackType=%d" , pid, 748 Log.d(TAG, "on connect callback, pid=%d", pid);
749 callbackType);
750 if (pid != NULL_PROCESS_HANDLE) { 749 if (pid != NULL_PROCESS_HANDLE) {
751 sBindingManager.addNewConnection(pid, connection); 750 sBindingManager.addNewConnection(pid, connection);
752 sServiceMap.put(pid, connection); 751 sServiceMap.put(pid, connection);
753 } 752 }
754 // If the connection fails and pid == 0, the Java-side c leanup was already 753 // If the connection fails and pid == 0, the Java-side c leanup was already
755 // handled by DeathCallback. We still have to call back to native for 754 // handled by DeathCallback. We still have to call back to native for
756 // cleanup there. 755 // cleanup there.
757 if (launchCallback != null) { // Will be null in Java in strumentation tests. 756 if (launchCallback != null) { // Will be null in Java in strumentation tests.
758 launchCallback.onChildProcessStarted(pid); 757 launchCallback.onChildProcessStarted(pid);
759 } 758 }
760 } 759 }
761 }; 760 };
762 761
763 assert callbackType != CALLBACK_FOR_UNKNOWN_PROCESS; 762 connection.setupConnection(
764 connection.setupConnection(commandLine, filesToBeMapped, 763 commandLine, filesToBeMapped, childProcessCallback, connectionCa llback);
765 createCallback(childProcessId, callbackType), connectionCallback );
766 } 764 }
767 765
768 /** 766 /**
769 * Terminates a child process. This may be called from any thread. 767 * Terminates a child process. This may be called from any thread.
770 * 768 *
771 * @param pid The pid (process handle) of the service connection obtained fr om {@link #start}. 769 * @param pid The pid (process handle) of the service connection obtained fr om {@link #start}.
772 */ 770 */
773 static void stop(int pid) { 771 static void stop(int pid) {
774 Log.d(TAG, "stopping child connection: pid=%d", pid); 772 Log.d(TAG, "stopping child connection: pid=%d", pid);
775 ChildProcessConnection connection = sServiceMap.remove(pid); 773 ChildProcessConnection connection = sServiceMap.remove(pid);
776 if (connection == null) { 774 if (connection == null) {
777 // Can happen for single process. 775 // Can happen for single process.
778 return; 776 return;
779 } 777 }
780 sBindingManager.clearConnection(pid); 778 sBindingManager.clearConnection(pid);
781 connection.stop(); 779 connection.stop();
782 freeConnection(connection); 780 freeConnection(connection);
783 } 781 }
784 782
785 /**
786 * This implementation is used to receive callbacks from the remote service.
787 */
788 private static IBinder createCallback(int childProcessId, int callbackType) {
789 return callbackType == CALLBACK_FOR_GPU_PROCESS ? new GpuProcessCallback () : null;
790 }
791
792 @VisibleForTesting 783 @VisibleForTesting
793 public static ChildProcessConnection startForTesting(Context context, String [] commandLine, 784 public static ChildProcessConnection startForTesting(Context context, String [] commandLine,
794 FileDescriptorInfo[] filesToMap, ChildProcessCreationParams params) { 785 FileDescriptorInfo[] filesToMap, ChildProcessCreationParams params) {
795 return startInternal(context, commandLine, 0, filesToMap, null, 786 return startInternal(context, commandLine, 0 /* childProcessId */, files ToMap,
796 CALLBACK_FOR_RENDERER_PROCESS, true, params); 787 null /* launchCallback */, null /* childProcessCallback */, true /* inSandbox */,
788 false /* alwaysInForeground */, params);
797 } 789 }
798 790
799 @VisibleForTesting 791 @VisibleForTesting
800 static ChildProcessConnection allocateBoundConnectionForTesting(Context cont ext, 792 static ChildProcessConnection allocateBoundConnectionForTesting(Context cont ext,
801 ChildProcessCreationParams creationParams) { 793 ChildProcessCreationParams creationParams) {
802 return allocateBoundConnection( 794 return allocateBoundConnection(
803 new SpawnData(false /* forWarmUp */, context, null /* commandLin e */, 795 new SpawnData(false /* forWarmUp */, context, null /* commandLin e */,
804 0 /* childProcessId */, null /* filesToBeMapped */, 796 0 /* childProcessId */, null /* filesToBeMapped */,
805 null /* LaunchCallback */, CALLBACK_FOR_RENDERER_PROCESS , 797 null /* LaunchCallback */, null /* childProcessCallback */,
806 true /* inSandbox */, creationParams), 798 true /* inSandbox */, false /* alwaysInForeground */, cr eationParams),
807 false /* alwaysInForeground */, null); 799 null /* startCallback */);
808 } 800 }
809 801
810 @VisibleForTesting 802 @VisibleForTesting
811 static ChildProcessConnection allocateConnectionForTesting(Context context, 803 static ChildProcessConnection allocateConnectionForTesting(Context context,
812 ChildProcessCreationParams creationParams) { 804 ChildProcessCreationParams creationParams) {
813 Bundle commonParams = new Bundle(); 805 Bundle commonParams = new Bundle();
814 commonParams.putParcelable( 806 commonParams.putParcelable(
815 ChildProcessConstants.EXTRA_LINKER_PARAMS, getLinkerParamsForNew Connection()); 807 ChildProcessConstants.EXTRA_LINKER_PARAMS, getLinkerParamsForNew Connection());
816 return allocateConnection( 808 return allocateConnection(
817 new SpawnData(false /* forWarmUp */, context, null /* commandLin e */, 809 new SpawnData(false /* forWarmUp */, context, null /* commandLin e */,
818 0 /* childProcessId */, null /* filesToBeMapped */, 810 0 /* childProcessId */, null /* filesToBeMapped */,
819 null /* LaunchCallback */, CALLBACK_FOR_RENDERER_PROCESS , 811 null /* launchCallback */, null /* childProcessCallback */,
820 true /* inSandbox */, creationParams), 812 true /* inSandbox */, false /* alwaysInForeground */, cr eationParams),
821 commonParams, false); 813 commonParams);
822 } 814 }
823 815
824 /** 816 /**
825 * Queue up a spawn requests for testing. 817 * Queue up a spawn requests for testing.
826 */ 818 */
827 @VisibleForTesting 819 @VisibleForTesting
828 static void enqueuePendingSpawnForTesting(Context context, String[] commandL ine, 820 static void enqueuePendingSpawnForTesting(Context context, String[] commandL ine,
829 ChildProcessCreationParams creationParams, boolean inSandbox) { 821 ChildProcessCreationParams creationParams, boolean inSandbox) {
830 String packageName = creationParams != null ? creationParams.getPackageN ame() 822 String packageName = creationParams != null ? creationParams.getPackageN ame()
831 : context.getPackageName(); 823 : context.getPackageName();
832 ChildConnectionAllocator allocator = 824 ChildConnectionAllocator allocator =
833 getAllocatorForTesting(context, packageName, inSandbox); 825 getAllocatorForTesting(context, packageName, inSandbox);
834 allocator.enqueuePendingQueueForTesting(new SpawnData(false /* forWarmUp */, context, 826 allocator.enqueuePendingQueueForTesting(new SpawnData(false /* forWarmUp */, context,
835 commandLine, 1, new FileDescriptorInfo[0], null, CALLBACK_FOR_RE NDERER_PROCESS, 827 commandLine, 1 /* childProcessId */, new FileDescriptorInfo[0],
836 true, creationParams)); 828 null /* launchCallback */, null /* childProcessCallback */, true /* inSandbox */,
829 false /* alwaysInForeground */, creationParams));
837 } 830 }
838 831
839 /** 832 /**
840 * @return the number of sandboxed connections of given {@link packageName} managed by the 833 * @return the number of sandboxed connections of given {@link packageName} managed by the
841 * allocator. 834 * allocator.
842 */ 835 */
843 @VisibleForTesting 836 @VisibleForTesting
844 static int allocatedSandboxedConnectionsCountForTesting(Context context, Str ing packageName) { 837 static int allocatedSandboxedConnectionsCountForTesting(Context context, Str ing packageName) {
845 initConnectionAllocatorsIfNecessary(context, true, packageName); 838 initConnectionAllocatorsIfNecessary(context, true, packageName);
846 return sSandboxedChildConnectionAllocatorMap.get(packageName) 839 return sSandboxedChildConnectionAllocatorMap.get(packageName)
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
885 878
886 try { 879 try {
887 ((ChildProcessConnectionImpl) sServiceMap.get(pid)).crashServiceForT esting(); 880 ((ChildProcessConnectionImpl) sServiceMap.get(pid)).crashServiceForT esting();
888 } catch (RemoteException ex) { 881 } catch (RemoteException ex) {
889 return false; 882 return false;
890 } 883 }
891 884
892 return true; 885 return true;
893 } 886 }
894 } 887 }
OLDNEW
« no previous file with comments | « no previous file | content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698