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

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

Issue 2689673007: android: Move PendingSpawnQueue into ChildConnectionAllocator (Closed)
Patch Set: comment Created 3 years, 10 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 | no next file » | 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 24 matching lines...) Expand all
35 35
36 import java.io.IOException; 36 import java.io.IOException;
37 import java.util.ArrayList; 37 import java.util.ArrayList;
38 import java.util.LinkedList; 38 import java.util.LinkedList;
39 import java.util.Map; 39 import java.util.Map;
40 import java.util.Queue; 40 import java.util.Queue;
41 import java.util.concurrent.ConcurrentHashMap; 41 import java.util.concurrent.ConcurrentHashMap;
42 42
43 /** 43 /**
44 * This class provides the method to start/stop ChildProcess called by native. 44 * This class provides the method to start/stop ChildProcess called by native.
45 *
46 * Note about threading. The threading here is complicated and not well document ed.
47 * Code can run on these threads: UI, Launcher, async thread pool, binder, and o ne-off
48 * background threads.
45 */ 49 */
46 @JNINamespace("content") 50 @JNINamespace("content")
47 public class ChildProcessLauncher { 51 public class ChildProcessLauncher {
48 private static final String TAG = "ChildProcLauncher"; 52 private static final String TAG = "ChildProcLauncher";
49 53
50 static final int CALLBACK_FOR_UNKNOWN_PROCESS = 0; 54 static final int CALLBACK_FOR_UNKNOWN_PROCESS = 0;
51 static final int CALLBACK_FOR_GPU_PROCESS = 1; 55 static final int CALLBACK_FOR_GPU_PROCESS = 1;
52 static final int CALLBACK_FOR_RENDERER_PROCESS = 2; 56 static final int CALLBACK_FOR_RENDERER_PROCESS = 2;
53 static final int CALLBACK_FOR_UTILITY_PROCESS = 3; 57 static final int CALLBACK_FOR_UTILITY_PROCESS = 3;
54 58
55 private static class ChildConnectionAllocator { 59 private static class ChildConnectionAllocator {
56 // Connections to services. Indices of the array correspond to the servi ce numbers. 60 // Connections to services. Indices of the array correspond to the servi ce numbers.
57 private final ChildProcessConnection[] mChildProcessConnections; 61 private final ChildProcessConnection[] mChildProcessConnections;
58 62
59 // The list of free (not bound) service indices. 63 // The list of free (not bound) service indices.
60 // SHOULD BE ACCESSED WITH mConnectionLock. 64 // SHOULD BE ACCESSED WITH mConnectionLock.
61 private final ArrayList<Integer> mFreeConnectionIndices; 65 private final ArrayList<Integer> mFreeConnectionIndices;
62 private final Object mConnectionLock = new Object(); 66 private final Object mConnectionLock = new Object();
63 67
64 private final String mChildClassName; 68 private final String mChildClassName;
65 private final boolean mInSandbox; 69 private final boolean mInSandbox;
66 // Each Allocator keeps a queue for the pending spawn data. Once a conne ction is free, we 70 // Each Allocator keeps a queue for the pending spawn data. Once a conne ction is free, we
67 // dequeue the pending spawn data from the same allocator as the connect ion. 71 // dequeue the pending spawn data from the same allocator as the connect ion.
68 private final PendingSpawnQueue mPendingSpawnQueue = new PendingSpawnQue ue(); 72 private final Queue<SpawnData> mPendingSpawnQueue = new LinkedList<>();
Maria 2017/02/14 00:59:41 Should this comment also mention that this uses mC
boliu 2017/02/14 01:34:20 Done.
69 73
70 public ChildConnectionAllocator(boolean inSandbox, int numChildServices, 74 public ChildConnectionAllocator(boolean inSandbox, int numChildServices,
71 String serviceClassName) { 75 String serviceClassName) {
72 mChildProcessConnections = new ChildProcessConnectionImpl[numChildSe rvices]; 76 mChildProcessConnections = new ChildProcessConnectionImpl[numChildSe rvices];
73 mFreeConnectionIndices = new ArrayList<Integer>(numChildServices); 77 mFreeConnectionIndices = new ArrayList<Integer>(numChildServices);
74 for (int i = 0; i < numChildServices; i++) { 78 for (int i = 0; i < numChildServices; i++) {
75 mFreeConnectionIndices.add(i); 79 mFreeConnectionIndices.add(i);
76 } 80 }
77 mChildClassName = serviceClassName; 81 mChildClassName = serviceClassName;
78 mInSandbox = inSandbox; 82 mInSandbox = inSandbox;
79 } 83 }
80 84
81 public ChildProcessConnection allocate( 85 // Allocate or enqueue. If there are no free slots, return null and enqu eue the spawn data.
82 Context context, ChildProcessConnection.DeathCallback deathCallb ack, 86 public ChildProcessConnection allocate(SpawnData spawnData,
83 ChromiumLinkerParams chromiumLinkerParams, 87 ChildProcessConnection.DeathCallback deathCallback,
84 boolean alwaysInForeground, 88 ChromiumLinkerParams chromiumLinkerParams, boolean alwaysInForeg round) {
85 ChildProcessCreationParams creationParams) { 89 assert spawnData.inSandbox() == mInSandbox;
86 synchronized (mConnectionLock) { 90 synchronized (mConnectionLock) {
87 if (mFreeConnectionIndices.isEmpty()) { 91 if (mFreeConnectionIndices.isEmpty()) {
88 Log.d(TAG, "Ran out of services to allocate."); 92 Log.d(TAG, "Ran out of services to allocate.");
93 if (!spawnData.forWarmUp()) {
94 mPendingSpawnQueue.add(spawnData);
95 }
89 return null; 96 return null;
90 } 97 }
91 int slot = mFreeConnectionIndices.remove(0); 98 int slot = mFreeConnectionIndices.remove(0);
92 assert mChildProcessConnections[slot] == null; 99 assert mChildProcessConnections[slot] == null;
93 mChildProcessConnections[slot] = new ChildProcessConnectionImpl( context, slot, 100 mChildProcessConnections[slot] = new ChildProcessConnectionImpl( spawnData.context(),
94 mInSandbox, deathCallback, mChildClassName, chromiumLink erParams, 101 slot, mInSandbox, deathCallback, mChildClassName, chromi umLinkerParams,
95 alwaysInForeground, creationParams); 102 alwaysInForeground, spawnData.getCreationParams());
96 Log.d(TAG, "Allocator allocated a connection, sandbox: %b, slot: %d", mInSandbox, 103 Log.d(TAG, "Allocator allocated a connection, sandbox: %b, slot: %d", mInSandbox,
97 slot); 104 slot);
98 return mChildProcessConnections[slot]; 105 return mChildProcessConnections[slot];
99 } 106 }
100 } 107 }
101 108
102 public void free(ChildProcessConnection connection) { 109 // Also return the first SpawnData in the pending queue, if any.
110 public SpawnData free(ChildProcessConnection connection) {
103 synchronized (mConnectionLock) { 111 synchronized (mConnectionLock) {
104 int slot = connection.getServiceNumber(); 112 int slot = connection.getServiceNumber();
105 if (mChildProcessConnections[slot] != connection) { 113 if (mChildProcessConnections[slot] != connection) {
106 int occupier = mChildProcessConnections[slot] == null 114 int occupier = mChildProcessConnections[slot] == null
107 ? -1 : mChildProcessConnections[slot].getServiceNumb er(); 115 ? -1 : mChildProcessConnections[slot].getServiceNumb er();
108 Log.e(TAG, "Unable to find connection to free in slot: %d " 116 Log.e(TAG, "Unable to find connection to free in slot: %d "
109 + "already occupied by service: %d", slot, occupier) ; 117 + "already occupied by service: %d", slot, occupier) ;
110 assert false; 118 assert false;
111 } else { 119 } else {
112 mChildProcessConnections[slot] = null; 120 mChildProcessConnections[slot] = null;
113 assert !mFreeConnectionIndices.contains(slot); 121 assert !mFreeConnectionIndices.contains(slot);
114 mFreeConnectionIndices.add(slot); 122 mFreeConnectionIndices.add(slot);
115 Log.d(TAG, "Allocator freed a connection, sandbox: %b, slot: %d", mInSandbox, 123 Log.d(TAG, "Allocator freed a connection, sandbox: %b, slot: %d", mInSandbox,
116 slot); 124 slot);
117 } 125 }
126 return mPendingSpawnQueue.poll();
118 } 127 }
119 } 128 }
120 129
121 public boolean isFreeConnectionAvailable() { 130 public boolean isFreeConnectionAvailable() {
122 synchronized (mConnectionLock) { 131 synchronized (mConnectionLock) {
123 return !mFreeConnectionIndices.isEmpty(); 132 return !mFreeConnectionIndices.isEmpty();
124 } 133 }
125 } 134 }
126 135
127 public PendingSpawnQueue getPendingSpawnQueue() {
128 return mPendingSpawnQueue;
129 }
130
131 /** @return the count of connections managed by the allocator */ 136 /** @return the count of connections managed by the allocator */
132 @VisibleForTesting 137 @VisibleForTesting
133 int allocatedConnectionsCountForTesting() { 138 int allocatedConnectionsCountForTesting() {
134 return mChildProcessConnections.length - mFreeConnectionIndices.size (); 139 return mChildProcessConnections.length - mFreeConnectionIndices.size ();
135 } 140 }
136 141
137 @VisibleForTesting 142 @VisibleForTesting
138 ChildProcessConnection[] connectionArrayForTesting() { 143 ChildProcessConnection[] connectionArrayForTesting() {
139 return mChildProcessConnections; 144 return mChildProcessConnections;
140 } 145 }
146
147 @VisibleForTesting
148 void enqueuePendingQueueForTesting(SpawnData spawnData) {
149 synchronized (mConnectionLock) {
150 mPendingSpawnQueue.add(spawnData);
151 }
152 }
153
154 @VisibleForTesting
155 int pendingSpawnsCountForTesting() {
156 synchronized (mConnectionLock) {
157 return mPendingSpawnQueue.size();
158 }
159 }
141 } 160 }
142 161
143 private static class PendingSpawnData { 162 private static class SpawnData {
163 private final boolean mForWarmup; // Do not queue up if failed.
144 private final Context mContext; 164 private final Context mContext;
145 private final String[] mCommandLine; 165 private final String[] mCommandLine;
146 private final int mChildProcessId; 166 private final int mChildProcessId;
147 private final FileDescriptorInfo[] mFilesToBeMapped; 167 private final FileDescriptorInfo[] mFilesToBeMapped;
148 private final long mClientContext; 168 private final long mClientContext;
149 private final int mCallbackType; 169 private final int mCallbackType;
150 private final boolean mInSandbox; 170 private final boolean mInSandbox;
151 private final ChildProcessCreationParams mCreationParams; 171 private final ChildProcessCreationParams mCreationParams;
152 172
153 private PendingSpawnData( 173 private SpawnData(boolean forWarmUp, Context context, String[] commandLi ne,
154 Context context, 174 int childProcessId, FileDescriptorInfo[] filesToBeMapped, long c lientContext,
155 String[] commandLine, 175 int callbackType, boolean inSandbox, ChildProcessCreationParams creationParams) {
156 int childProcessId, 176 mForWarmup = forWarmUp;
157 FileDescriptorInfo[] filesToBeMapped,
158 long clientContext,
159 int callbackType,
160 boolean inSandbox,
161 ChildProcessCreationParams creationParams) {
162 mContext = context; 177 mContext = context;
163 mCommandLine = commandLine; 178 mCommandLine = commandLine;
164 mChildProcessId = childProcessId; 179 mChildProcessId = childProcessId;
165 mFilesToBeMapped = filesToBeMapped; 180 mFilesToBeMapped = filesToBeMapped;
166 mClientContext = clientContext; 181 mClientContext = clientContext;
167 mCallbackType = callbackType; 182 mCallbackType = callbackType;
168 mInSandbox = inSandbox; 183 mInSandbox = inSandbox;
169 mCreationParams = creationParams; 184 mCreationParams = creationParams;
170 } 185 }
171 186
187 private boolean forWarmUp() {
188 return mForWarmup;
189 }
190
172 private Context context() { 191 private Context context() {
173 return mContext; 192 return mContext;
174 } 193 }
175 private String[] commandLine() { 194 private String[] commandLine() {
176 return mCommandLine; 195 return mCommandLine;
177 } 196 }
178 private int childProcessId() { 197 private int childProcessId() {
179 return mChildProcessId; 198 return mChildProcessId;
180 } 199 }
181 private FileDescriptorInfo[] filesToBeMapped() { 200 private FileDescriptorInfo[] filesToBeMapped() {
182 return mFilesToBeMapped; 201 return mFilesToBeMapped;
183 } 202 }
184 private long clientContext() { 203 private long clientContext() {
185 return mClientContext; 204 return mClientContext;
186 } 205 }
187 private int callbackType() { 206 private int callbackType() {
188 return mCallbackType; 207 return mCallbackType;
189 } 208 }
190 private boolean inSandbox() { 209 private boolean inSandbox() {
191 return mInSandbox; 210 return mInSandbox;
192 } 211 }
193 private ChildProcessCreationParams getCreationParams() { 212 private ChildProcessCreationParams getCreationParams() {
194 return mCreationParams; 213 return mCreationParams;
195 } 214 }
196 } 215 }
197 216
198 private static class PendingSpawnQueue {
199 // The list of pending process spawn requests and its lock.
200 // Operations on this queue must be atomical w.r.t. free connections upd ates.
201 private Queue<PendingSpawnData> mPendingSpawns = new LinkedList<PendingS pawnData>();
202 final Object mPendingSpawnsLock = new Object();
203
204 /**
205 * Queue up a spawn requests to be processed once a free service is avai lable.
206 * Called when a spawn is requested while we are at the capacity.
207 */
208 public void enqueueLocked(final PendingSpawnData pendingSpawn) {
209 assert Thread.holdsLock(mPendingSpawnsLock);
210 mPendingSpawns.add(pendingSpawn);
211 }
212
213 /**
214 * Pop the next request from the queue. Called when a free service is av ailable.
215 * @return the next spawn request waiting in the queue.
216 */
217 public PendingSpawnData dequeueLocked() {
218 assert Thread.holdsLock(mPendingSpawnsLock);
219 return mPendingSpawns.poll();
220 }
221
222 /** @return the count of pending spawns in the queue */
223 public int sizeLocked() {
224 assert Thread.holdsLock(mPendingSpawnsLock);
225 return mPendingSpawns.size();
226 }
227 }
228
229 // Service class for child process. 217 // Service class for child process.
230 // Map from package name to ChildConnectionAllocator. 218 // Map from package name to ChildConnectionAllocator.
231 private static Map<String, ChildConnectionAllocator> sSandboxedChildConnecti onAllocatorMap; 219 private static Map<String, ChildConnectionAllocator> sSandboxedChildConnecti onAllocatorMap;
232 // As the default value it uses PrivilegedProcessService0. 220 // As the default value it uses PrivilegedProcessService0.
233 private static ChildConnectionAllocator sPrivilegedChildConnectionAllocator; 221 private static ChildConnectionAllocator sPrivilegedChildConnectionAllocator;
234 222
235 private static final String NUM_SANDBOXED_SERVICES_KEY = 223 private static final String NUM_SANDBOXED_SERVICES_KEY =
236 "org.chromium.content.browser.NUM_SANDBOXED_SERVICES"; 224 "org.chromium.content.browser.NUM_SANDBOXED_SERVICES";
237 private static final String NUM_PRIVILEGED_SERVICES_KEY = 225 private static final String NUM_PRIVILEGED_SERVICES_KEY =
238 "org.chromium.content.browser.NUM_PRIVILEGED_SERVICES"; 226 "org.chromium.content.browser.NUM_PRIVILEGED_SERVICES";
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 * Otherwise, always calls {@link initConnectionAllocatorsIfNecessary} first . 337 * Otherwise, always calls {@link initConnectionAllocatorsIfNecessary} first .
350 */ 338 */
351 private static ChildConnectionAllocator getConnectionAllocator( 339 private static ChildConnectionAllocator getConnectionAllocator(
352 String packageName, boolean inSandbox) { 340 String packageName, boolean inSandbox) {
353 if (!inSandbox) { 341 if (!inSandbox) {
354 return sPrivilegedChildConnectionAllocator; 342 return sPrivilegedChildConnectionAllocator;
355 } 343 }
356 return sSandboxedChildConnectionAllocatorMap.get(packageName); 344 return sSandboxedChildConnectionAllocatorMap.get(packageName);
357 } 345 }
358 346
359 /** 347 private static ChildConnectionAllocator getAllocatorForTesting(
360 * Get the PendingSpawnQueue of the Allocator. Initialize the Allocator if n eeded. 348 Context context, String packageName, boolean inSandbox) {
361 */
362 private static PendingSpawnQueue getPendingSpawnQueue(Context context, Strin g packageName,
363 boolean inSandbox) {
364 initConnectionAllocatorsIfNecessary(context, inSandbox, packageName); 349 initConnectionAllocatorsIfNecessary(context, inSandbox, packageName);
365 return getConnectionAllocator(packageName, inSandbox).getPendingSpawnQue ue(); 350 return getConnectionAllocator(packageName, inSandbox);
366 } 351 }
367 352
368 private static ChildProcessConnection allocateConnection(Context context, bo olean inSandbox, 353 private static ChildProcessConnection allocateConnection(SpawnData spawnData ,
369 ChromiumLinkerParams chromiumLinkerParams, boolean alwaysInForegroun d, 354 ChromiumLinkerParams chromiumLinkerParams, boolean alwaysInForegroun d) {
370 ChildProcessCreationParams creationParams) {
371 ChildProcessConnection.DeathCallback deathCallback = 355 ChildProcessConnection.DeathCallback deathCallback =
372 new ChildProcessConnection.DeathCallback() { 356 new ChildProcessConnection.DeathCallback() {
373 @Override 357 @Override
374 public void onChildProcessDied(ChildProcessConnection connec tion) { 358 public void onChildProcessDied(ChildProcessConnection connec tion) {
375 if (connection.getPid() != 0) { 359 if (connection.getPid() != 0) {
376 stop(connection.getPid()); 360 stop(connection.getPid());
377 } else { 361 } else {
378 freeConnection(connection); 362 freeConnection(connection);
379 } 363 }
380 } 364 }
381 }; 365 };
382 String packageName = creationParams != null ? creationParams.getPackageN ame() 366 final ChildProcessCreationParams creationParams = spawnData.getCreationP arams();
383 : context.getPackageName(); 367 final Context context = spawnData.context();
368 final boolean inSandbox = spawnData.inSandbox();
369 String packageName =
370 creationParams != null ? creationParams.getPackageName() : conte xt.getPackageName();
384 initConnectionAllocatorsIfNecessary(context, inSandbox, packageName); 371 initConnectionAllocatorsIfNecessary(context, inSandbox, packageName);
385 return getConnectionAllocator(packageName, inSandbox) 372 return getConnectionAllocator(packageName, inSandbox)
386 .allocate(context, deathCallback, chromiumLinkerParams, alwaysIn Foreground, 373 .allocate(spawnData, deathCallback, chromiumLinkerParams, always InForeground);
387 creationParams);
388 } 374 }
389 375
390 private static boolean sLinkerInitialized; 376 private static boolean sLinkerInitialized;
391 private static long sLinkerLoadAddress; 377 private static long sLinkerLoadAddress;
392 378
393 private static ChromiumLinkerParams getLinkerParamsForNewConnection() { 379 private static ChromiumLinkerParams getLinkerParamsForNewConnection() {
394 if (!sLinkerInitialized) { 380 if (!sLinkerInitialized) {
395 if (Linker.isUsed()) { 381 if (Linker.isUsed()) {
396 sLinkerLoadAddress = Linker.getInstance().getBaseLoadAddress(); 382 sLinkerLoadAddress = Linker.getInstance().getBaseLoadAddress();
397 if (sLinkerLoadAddress == 0) { 383 if (sLinkerLoadAddress == 0) {
(...skipping 12 matching lines...) Expand all
410 return new ChromiumLinkerParams(sLinkerLoadAddress, 396 return new ChromiumLinkerParams(sLinkerLoadAddress,
411 waitForSharedRelros, 397 waitForSharedRelros,
412 linker.getTestRunnerClassNameForTest ing(), 398 linker.getTestRunnerClassNameForTest ing(),
413 linker.getImplementationForTesting() ); 399 linker.getImplementationForTesting() );
414 } else { 400 } else {
415 return new ChromiumLinkerParams(sLinkerLoadAddress, 401 return new ChromiumLinkerParams(sLinkerLoadAddress,
416 waitForSharedRelros); 402 waitForSharedRelros);
417 } 403 }
418 } 404 }
419 405
420 private static ChildProcessConnection allocateBoundConnection(Context contex t, 406 private static ChildProcessConnection allocateBoundConnection(SpawnData spaw nData,
421 String[] commandLine, boolean inSandbox, boolean alwaysInForeground, 407 boolean alwaysInForeground, ChildProcessConnection.StartCallback sta rtCallback) {
422 ChildProcessCreationParams creationParams, 408 final Context context = spawnData.context();
423 ChildProcessConnection.StartCallback startCallback) { 409 final String[] commandLine = spawnData.commandLine();
410 final boolean inSandbox = spawnData.inSandbox();
411 final ChildProcessCreationParams creationParams = spawnData.getCreationP arams();
424 ChromiumLinkerParams chromiumLinkerParams = getLinkerParamsForNewConnect ion(); 412 ChromiumLinkerParams chromiumLinkerParams = getLinkerParamsForNewConnect ion();
425 ChildProcessConnection connection = allocateConnection( 413 ChildProcessConnection connection =
426 context, inSandbox, chromiumLinkerParams, alwaysInForeground, cr eationParams); 414 allocateConnection(spawnData, chromiumLinkerParams, alwaysInFore ground);
427 if (connection != null) { 415 if (connection != null) {
428 connection.start(commandLine, startCallback); 416 connection.start(commandLine, startCallback);
429 417
430 String packageName = creationParams != null ? creationParams.getPack ageName() 418 String packageName = creationParams != null ? creationParams.getPack ageName()
431 : context.getPackageName(); 419 : context.getPackageName ();
432 if (inSandbox && !getConnectionAllocator(packageName, inSandbox) 420 if (inSandbox
433 .isFreeConnectionAvailable()) { 421 && !getConnectionAllocator(packageName, inSandbox)
422 .isFreeConnectionAvailable()) {
434 // Proactively releases all the moderate bindings once all the s andboxed services 423 // Proactively releases all the moderate bindings once all the s andboxed services
435 // are allocated, which will be very likely to have some of them killed by OOM 424 // are allocated, which will be very likely to have some of them killed by OOM
436 // killer. 425 // killer.
437 sBindingManager.releaseAllModerateBindings(); 426 sBindingManager.releaseAllModerateBindings();
438 } 427 }
439 } 428 }
440 return connection; 429 return connection;
441 } 430 }
442 431
443 private static final long FREE_CONNECTION_DELAY_MILLIS = 1; 432 private static final long FREE_CONNECTION_DELAY_MILLIS = 1;
444 433
445 private static void freeConnection(ChildProcessConnection connection) { 434 private static void freeConnection(ChildProcessConnection connection) {
446 synchronized (sSpareConnectionLock) { 435 synchronized (sSpareConnectionLock) {
447 if (connection.equals(sSpareSandboxedConnection)) sSpareSandboxedCon nection = null; 436 if (connection.equals(sSpareSandboxedConnection)) sSpareSandboxedCon nection = null;
448 } 437 }
449 438
450 // Freeing a service should be delayed. This is so that we avoid immedia tely reusing the 439 // Freeing a service should be delayed. This is so that we avoid immedia tely reusing the
451 // freed service (see http://crbug.com/164069): the framework might keep a service process 440 // freed service (see http://crbug.com/164069): the framework might keep a service process
452 // alive when it's been unbound for a short time. If a new connection to the same service 441 // alive when it's been unbound for a short time. If a new connection to the same service
453 // is bound at that point, the process is reused and bad things happen ( mostly static 442 // is bound at that point, the process is reused and bad things happen ( mostly static
454 // variables are set when we don't expect them to). 443 // variables are set when we don't expect them to).
455 final ChildProcessConnection conn = connection; 444 final ChildProcessConnection conn = connection;
456 ThreadUtils.postOnUiThreadDelayed(new Runnable() { 445 ThreadUtils.postOnUiThreadDelayed(new Runnable() {
457 @Override 446 @Override
458 public void run() { 447 public void run() {
459 final PendingSpawnData pendingSpawn = freeConnectionAndDequeuePe nding(conn); 448 final SpawnData pendingSpawn = freeConnectionAndDequeuePending(c onn);
460 if (pendingSpawn != null) { 449 if (pendingSpawn != null) {
461 new Thread(new Runnable() { 450 new Thread(new Runnable() {
462 @Override 451 @Override
463 public void run() { 452 public void run() {
464 startInternal(pendingSpawn.context(), pendingSpawn.c ommandLine(), 453 startInternal(pendingSpawn.context(), pendingSpawn.c ommandLine(),
465 pendingSpawn.childProcessId(), pendingSpawn. filesToBeMapped(), 454 pendingSpawn.childProcessId(), pendingSpawn. filesToBeMapped(),
466 pendingSpawn.clientContext(), pendingSpawn.c allbackType(), 455 pendingSpawn.clientContext(), pendingSpawn.c allbackType(),
467 pendingSpawn.inSandbox(), pendingSpawn.getCr eationParams()); 456 pendingSpawn.inSandbox(), pendingSpawn.getCr eationParams());
468 } 457 }
469 }).start(); 458 }).start();
470 } 459 }
471 } 460 }
472 }, FREE_CONNECTION_DELAY_MILLIS); 461 }, FREE_CONNECTION_DELAY_MILLIS);
473 } 462 }
474 463
475 private static PendingSpawnData freeConnectionAndDequeuePending(ChildProcess Connection conn) { 464 private static SpawnData freeConnectionAndDequeuePending(ChildProcessConnect ion conn) {
476 ChildConnectionAllocator allocator = getConnectionAllocator( 465 ChildConnectionAllocator allocator = getConnectionAllocator(
477 conn.getPackageName(), conn.isInSandbox()); 466 conn.getPackageName(), conn.isInSandbox());
478 assert allocator != null; 467 assert allocator != null;
479 PendingSpawnQueue pendingSpawnQueue = allocator.getPendingSpawnQueue(); 468 return allocator.free(conn);
480 synchronized (pendingSpawnQueue.mPendingSpawnsLock) {
481 allocator.free(conn);
482 return pendingSpawnQueue.dequeueLocked();
483 }
484 } 469 }
485 470
486 // Represents an invalid process handle; same as base/process/process.h kNul lProcessHandle. 471 // Represents an invalid process handle; same as base/process/process.h kNul lProcessHandle.
487 private static final int NULL_PROCESS_HANDLE = 0; 472 private static final int NULL_PROCESS_HANDLE = 0;
488 473
489 // Map from pid to ChildService connection. 474 // Map from pid to ChildService connection.
490 private static Map<Integer, ChildProcessConnection> sServiceMap = 475 private static Map<Integer, ChildProcessConnection> sServiceMap =
491 new ConcurrentHashMap<Integer, ChildProcessConnection>(); 476 new ConcurrentHashMap<Integer, ChildProcessConnection>();
492 477
493 // Lock and monitor for these members {{{ 478 // Lock and monitor for these members {{{
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
605 @Override 590 @Override
606 public void onChildStartFailed() { 591 public void onChildStartFailed() {
607 Log.e(TAG, "Failed to warm up the spare sandbox service"); 592 Log.e(TAG, "Failed to warm up the spare sandbox service");
608 synchronized (sSpareConnectionLock) { 593 synchronized (sSpareConnectionLock) {
609 sSpareSandboxedConnection = null; 594 sSpareSandboxedConnection = null;
610 sSpareConnectionStarting = false; 595 sSpareConnectionStarting = false;
611 sSpareConnectionLock.notify(); 596 sSpareConnectionLock.notify();
612 } 597 }
613 } 598 }
614 }; 599 };
615 sSpareSandboxedConnection = allocateBoundConnection(context, nul l, true, false, 600 SpawnData spawnData = new SpawnData(true /* forWarmUp*/, context ,
616 params, startCallback); 601 null /* commandLine */, -1 /* child process id */,
602 null /* filesToBeMapped */, 0 /* clientContext */,
603 CALLBACK_FOR_RENDERER_PROCESS, true /* inSandbox */, par ams);
Maria 2017/02/14 00:59:41 these new calls with a bunch of comments make me t
boliu 2017/02/14 01:34:20 Hmm.. If we want to force caller to make a decisio
604 sSpareSandboxedConnection = allocateBoundConnection(
605 spawnData, false /* alwaysInForeground */, startCallback );
617 } 606 }
618 } 607 }
619 } 608 }
620 609
621 @CalledByNative 610 @CalledByNative
622 private static FileDescriptorInfo makeFdInfo( 611 private static FileDescriptorInfo makeFdInfo(
623 int id, int fd, boolean autoClose, long offset, long size) { 612 int id, int fd, boolean autoClose, long offset, long size) {
624 ParcelFileDescriptor pFd; 613 ParcelFileDescriptor pFd;
625 if (autoClose) { 614 if (autoClose) {
626 // Adopt the FD, it will be closed when we close the ParcelFileDescr iptor. 615 // Adopt the FD, it will be closed when we close the ParcelFileDescr iptor.
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
715 } catch (InterruptedException ex) { 704 } catch (InterruptedException ex) {
716 } 705 }
717 } 706 }
718 allocatedConnection = sSpareSandboxedConnection; 707 allocatedConnection = sSpareSandboxedConnection;
719 sSpareSandboxedConnection = null; 708 sSpareSandboxedConnection = null;
720 } 709 }
721 } 710 }
722 if (allocatedConnection == null) { 711 if (allocatedConnection == null) {
723 boolean alwaysInForeground = false; 712 boolean alwaysInForeground = false;
724 if (callbackType == CALLBACK_FOR_GPU_PROCESS) alwaysInForeground = true; 713 if (callbackType == CALLBACK_FOR_GPU_PROCESS) alwaysInForeground = true;
725 PendingSpawnQueue pendingSpawnQueue = getPendingSpawnQueue(
726 context, packageName, inSandbox);
727 ChildProcessConnection.StartCallback startCallback = 714 ChildProcessConnection.StartCallback startCallback =
728 new ChildProcessConnection.StartCallback() { 715 new ChildProcessConnection.StartCallback() {
729 @Override 716 @Override
730 public void onChildStarted() {} 717 public void onChildStarted() {}
731 718
732 @Override 719 @Override
733 public void onChildStartFailed() { 720 public void onChildStartFailed() {
734 Log.e(TAG, "ChildProcessConnection.start failed, trying again"); 721 Log.e(TAG, "ChildProcessConnection.start failed, trying again");
735 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runna ble() { 722 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runna ble() {
736 @Override 723 @Override
737 public void run() { 724 public void run() {
738 // The child process may already be boun d to another client 725 // The child process may already be boun d to another client
739 // (this can happen if multi-process Web View is used in more 726 // (this can happen if multi-process Web View is used in more
740 // than one process), so try starting th e process again. 727 // than one process), so try starting th e process again.
741 // This connection that failed to start has not been freed, 728 // This connection that failed to start has not been freed,
742 // so a new bound connection will be all ocated. 729 // so a new bound connection will be all ocated.
743 startInternal(context, commandLine, chil dProcessId, 730 startInternal(context, commandLine, chil dProcessId,
744 filesToBeMapped, clientContext, callbackType, 731 filesToBeMapped, clientContext, callbackType,
745 inSandbox, creationParams); 732 inSandbox, creationParams);
746 } 733 }
747 }); 734 });
748 } 735 }
749 }; 736 };
750 synchronized (pendingSpawnQueue.mPendingSpawnsLock) { 737
751 allocatedConnection = allocateBoundConnection( 738 SpawnData spawnData = new SpawnData(false /* forWarmUp */, conte xt, commandLine,
752 context, commandLine, inSandbox, alwaysInForeground, creationParams, 739 childProcessId, filesToBeMapped, clientContext, callback Type, inSandbox,
753 startCallback); 740 creationParams);
754 if (allocatedConnection == null) { 741 allocatedConnection =
755 Log.d(TAG, "Allocation of new service failed. Queuing up pending spawn."); 742 allocateBoundConnection(spawnData, alwaysInForeground, s tartCallback);
756 pendingSpawnQueue.enqueueLocked(new PendingSpawnData(con text, commandLine, 743 if (allocatedConnection == null) {
757 childProcessId, filesToBeMapped, clientContext, 744 return null;
758 callbackType, inSandbox, creationParams));
759 return null;
760 }
761 } 745 }
762 } 746 }
763 747
764 Log.d(TAG, "Setting up connection to process: slot=%d", 748 Log.d(TAG, "Setting up connection to process: slot=%d",
765 allocatedConnection.getServiceNumber()); 749 allocatedConnection.getServiceNumber());
766 triggerConnectionSetup(allocatedConnection, commandLine, childProces sId, 750 triggerConnectionSetup(allocatedConnection, commandLine, childProces sId,
767 filesToBeMapped, callbackType, clientContext); 751 filesToBeMapped, callbackType, clientContext);
768 return allocatedConnection; 752 return allocatedConnection;
769 } finally { 753 } finally {
770 TraceEvent.end("ChildProcessLauncher.startInternal"); 754 TraceEvent.end("ChildProcessLauncher.startInternal");
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
886 @VisibleForTesting 870 @VisibleForTesting
887 public static ChildProcessConnection startForTesting(Context context, String [] commandLine, 871 public static ChildProcessConnection startForTesting(Context context, String [] commandLine,
888 FileDescriptorInfo[] filesToMap, ChildProcessCreationParams params) { 872 FileDescriptorInfo[] filesToMap, ChildProcessCreationParams params) {
889 return startInternal(context, commandLine, 0, filesToMap, 0, 873 return startInternal(context, commandLine, 0, filesToMap, 0,
890 CALLBACK_FOR_RENDERER_PROCESS, true, params); 874 CALLBACK_FOR_RENDERER_PROCESS, true, params);
891 } 875 }
892 876
893 @VisibleForTesting 877 @VisibleForTesting
894 static ChildProcessConnection allocateBoundConnectionForTesting(Context cont ext, 878 static ChildProcessConnection allocateBoundConnectionForTesting(Context cont ext,
895 ChildProcessCreationParams creationParams) { 879 ChildProcessCreationParams creationParams) {
896 return allocateBoundConnection(context, null, true, false, creationParam s, null); 880 return allocateBoundConnection(
881 new SpawnData(false /* forWarmUp */, context, null /* commandLin e */,
882 0 /* childProcessId */, null /* filesToBeMapped */, 0 /* clientContext */,
883 CALLBACK_FOR_RENDERER_PROCESS, true /* inSandbox */, cre ationParams),
884 false /* alwaysInForeground */, null);
897 } 885 }
898 886
899 @VisibleForTesting 887 @VisibleForTesting
900 static ChildProcessConnection allocateConnectionForTesting(Context context, 888 static ChildProcessConnection allocateConnectionForTesting(Context context,
901 ChildProcessCreationParams creationParams) { 889 ChildProcessCreationParams creationParams) {
902 return allocateConnection( 890 return allocateConnection(
903 context, true, getLinkerParamsForNewConnection(), false, creatio nParams); 891 new SpawnData(false /* forWarmUp */, context, null /* commandLin e */,
892 0 /* childProcessId */, null /* filesToBeMapped */, 0 /* clientContext */,
893 CALLBACK_FOR_RENDERER_PROCESS, true /* inSandbox */, cre ationParams),
894 getLinkerParamsForNewConnection(), false);
904 } 895 }
905 896
906 /** 897 /**
907 * Queue up a spawn requests for testing. 898 * Queue up a spawn requests for testing.
908 */ 899 */
909 @VisibleForTesting 900 @VisibleForTesting
910 static void enqueuePendingSpawnForTesting(Context context, String[] commandL ine, 901 static void enqueuePendingSpawnForTesting(Context context, String[] commandL ine,
911 ChildProcessCreationParams creationParams, boolean inSandbox) { 902 ChildProcessCreationParams creationParams, boolean inSandbox) {
912 String packageName = creationParams != null ? creationParams.getPackageN ame() 903 String packageName = creationParams != null ? creationParams.getPackageN ame()
913 : context.getPackageName(); 904 : context.getPackageName();
914 PendingSpawnQueue pendingSpawnQueue = getPendingSpawnQueue(context, 905 ChildConnectionAllocator allocator =
915 packageName, inSandbox); 906 getAllocatorForTesting(context, packageName, inSandbox);
916 synchronized (pendingSpawnQueue.mPendingSpawnsLock) { 907 allocator.enqueuePendingQueueForTesting(new SpawnData(false /* forWarmUp */, context,
917 pendingSpawnQueue.enqueueLocked(new PendingSpawnData(context, comman dLine, 1, 908 commandLine, 1, new FileDescriptorInfo[0], 0, CALLBACK_FOR_RENDE RER_PROCESS, true,
918 new FileDescriptorInfo[0], 0, CALLBACK_FOR_RENDERER_PROCESS, true, 909 creationParams));
919 creationParams));
920 }
921 } 910 }
922 911
923 /** 912 /**
924 * @return the number of sandboxed connections of given {@link packageName} managed by the 913 * @return the number of sandboxed connections of given {@link packageName} managed by the
925 * allocator. 914 * allocator.
926 */ 915 */
927 @VisibleForTesting 916 @VisibleForTesting
928 static int allocatedSandboxedConnectionsCountForTesting(Context context, Str ing packageName) { 917 static int allocatedSandboxedConnectionsCountForTesting(Context context, Str ing packageName) {
929 initConnectionAllocatorsIfNecessary(context, true, packageName); 918 initConnectionAllocatorsIfNecessary(context, true, packageName);
930 return sSandboxedChildConnectionAllocatorMap.get(packageName) 919 return sSandboxedChildConnectionAllocatorMap.get(packageName)
931 .allocatedConnectionsCountForTesting(); 920 .allocatedConnectionsCountForTesting();
932 } 921 }
933 922
934 /** 923 /**
935 * @return gets the service connection array for a specific package name. 924 * @return gets the service connection array for a specific package name.
936 */ 925 */
937 @VisibleForTesting 926 @VisibleForTesting
938 static ChildProcessConnection[] getSandboxedConnectionArrayForTesting( 927 static ChildProcessConnection[] getSandboxedConnectionArrayForTesting(String packageName) {
939 String packageName) {
940 return sSandboxedChildConnectionAllocatorMap.get(packageName).connection ArrayForTesting(); 928 return sSandboxedChildConnectionAllocatorMap.get(packageName).connection ArrayForTesting();
941 } 929 }
942 930
943 /** @return the count of services set up and working */ 931 /** @return the count of services set up and working */
944 @VisibleForTesting 932 @VisibleForTesting
945 static int connectedServicesCountForTesting() { 933 static int connectedServicesCountForTesting() {
946 return sServiceMap.size(); 934 return sServiceMap.size();
947 } 935 }
948 936
949 /** 937 /**
950 * @param context The context. 938 * @param context The context.
951 * @param packageName The package name of the {@link ChildProcessAlocator}. 939 * @param packageName The package name of the {@link ChildProcessAlocator}.
952 * @param inSandbox Whether the connection is sandboxed. 940 * @param inSandbox Whether the connection is sandboxed.
953 * @return the count of pending spawns in the queue. 941 * @return the count of pending spawns in the queue.
954 */ 942 */
955 @VisibleForTesting 943 @VisibleForTesting
956 static int pendingSpawnsCountForTesting(Context context, String packageName, 944 static int pendingSpawnsCountForTesting(
957 boolean inSandbox) { 945 Context context, String packageName, boolean inSandbox) {
958 PendingSpawnQueue pendingSpawnQueue = getPendingSpawnQueue(context, pack ageName, inSandbox); 946 ChildConnectionAllocator allocator =
959 synchronized (pendingSpawnQueue.mPendingSpawnsLock) { 947 getAllocatorForTesting(context, packageName, inSandbox);
960 return pendingSpawnQueue.sizeLocked(); 948 return allocator.pendingSpawnsCountForTesting();
961 }
962 } 949 }
963 950
964 /** 951 /**
965 * Kills the child process for testing. 952 * Kills the child process for testing.
966 * @return true iff the process was killed as expected 953 * @return true iff the process was killed as expected
967 */ 954 */
968 @VisibleForTesting 955 @VisibleForTesting
969 public static boolean crashProcessForTesting(int pid) { 956 public static boolean crashProcessForTesting(int pid) {
970 if (sServiceMap.get(pid) == null) return false; 957 if (sServiceMap.get(pid) == null) return false;
971 958
972 try { 959 try {
973 ((ChildProcessConnectionImpl) sServiceMap.get(pid)).crashServiceForT esting(); 960 ((ChildProcessConnectionImpl) sServiceMap.get(pid)).crashServiceForT esting();
974 } catch (RemoteException ex) { 961 } catch (RemoteException ex) {
975 return false; 962 return false;
976 } 963 }
977 964
978 return true; 965 return true;
979 } 966 }
980 967
981 private static native void nativeOnChildProcessStarted(long clientContext, i nt pid); 968 private static native void nativeOnChildProcessStarted(long clientContext, i nt pid);
982 private static native void nativeCompleteScopedSurfaceRequest( 969 private static native void nativeCompleteScopedSurfaceRequest(
983 UnguessableToken requestToken, Surface surface); 970 UnguessableToken requestToken, Surface surface);
984 private static native boolean nativeIsSingleProcess(); 971 private static native boolean nativeIsSingleProcess();
985 private static native Surface nativeGetViewSurface(int surfaceId); 972 private static native Surface nativeGetViewSurface(int surfaceId);
986 } 973 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698