Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |