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 25 matching lines...) Expand all Loading... | |
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 Loading... | |
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 Loading... | |
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 |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
344 return sSandboxedChildConnectionAllocatorMap.get(packageName); | 343 return sSandboxedChildConnectionAllocatorMap.get(packageName); |
345 } | 344 } |
346 | 345 |
347 private static ChildConnectionAllocator getAllocatorForTesting( | 346 private static ChildConnectionAllocator getAllocatorForTesting( |
348 Context context, String packageName, boolean inSandbox) { | 347 Context context, String packageName, boolean inSandbox) { |
349 initConnectionAllocatorsIfNecessary(context, inSandbox, packageName); | 348 initConnectionAllocatorsIfNecessary(context, inSandbox, packageName); |
350 return getConnectionAllocator(packageName, inSandbox); | 349 return getConnectionAllocator(packageName, inSandbox); |
351 } | 350 } |
352 | 351 |
353 private static ChildProcessConnection allocateConnection( | 352 private static ChildProcessConnection allocateConnection( |
354 SpawnData spawnData, Bundle childProcessCommonParams, boolean always InForeground) { | 353 SpawnData spawnData, Bundle childProcessCommonParams) { |
355 ChildProcessConnection.DeathCallback deathCallback = | 354 ChildProcessConnection.DeathCallback deathCallback = |
356 new ChildProcessConnection.DeathCallback() { | 355 new ChildProcessConnection.DeathCallback() { |
357 @Override | 356 @Override |
358 public void onChildProcessDied(ChildProcessConnection connec tion) { | 357 public void onChildProcessDied(ChildProcessConnection connec tion) { |
359 if (connection.getPid() != 0) { | 358 if (connection.getPid() != 0) { |
360 stop(connection.getPid()); | 359 stop(connection.getPid()); |
361 } else { | 360 } else { |
362 freeConnection(connection); | 361 freeConnection(connection); |
363 } | 362 } |
364 } | 363 } |
365 }; | 364 }; |
366 final ChildProcessCreationParams creationParams = spawnData.getCreationP arams(); | 365 final ChildProcessCreationParams creationParams = spawnData.getCreationP arams(); |
367 final Context context = spawnData.context(); | 366 final Context context = spawnData.getContext(); |
368 final boolean inSandbox = spawnData.inSandbox(); | 367 final boolean inSandbox = spawnData.isInSandbox(); |
369 String packageName = | 368 String packageName = |
370 creationParams != null ? creationParams.getPackageName() : conte xt.getPackageName(); | 369 creationParams != null ? creationParams.getPackageName() : conte xt.getPackageName(); |
371 initConnectionAllocatorsIfNecessary(context, inSandbox, packageName); | 370 initConnectionAllocatorsIfNecessary(context, inSandbox, packageName); |
372 return getConnectionAllocator(packageName, inSandbox) | 371 return getConnectionAllocator(packageName, inSandbox) |
373 .allocate(spawnData, deathCallback, childProcessCommonParams, al waysInForeground); | 372 .allocate(spawnData, deathCallback, childProcessCommonParams); |
374 } | 373 } |
375 | 374 |
376 private static boolean sLinkerInitialized; | 375 private static boolean sLinkerInitialized; |
377 private static long sLinkerLoadAddress; | 376 private static long sLinkerLoadAddress; |
378 | 377 |
379 private static ChromiumLinkerParams getLinkerParamsForNewConnection() { | 378 private static ChromiumLinkerParams getLinkerParamsForNewConnection() { |
380 if (!sLinkerInitialized) { | 379 if (!sLinkerInitialized) { |
381 if (Linker.isUsed()) { | 380 if (Linker.isUsed()) { |
382 sLinkerLoadAddress = Linker.getInstance().getBaseLoadAddress(); | 381 sLinkerLoadAddress = Linker.getInstance().getBaseLoadAddress(); |
383 if (sLinkerLoadAddress == 0) { | 382 if (sLinkerLoadAddress == 0) { |
(...skipping 12 matching lines...) Expand all Loading... | |
396 return new ChromiumLinkerParams(sLinkerLoadAddress, | 395 return new ChromiumLinkerParams(sLinkerLoadAddress, |
397 waitForSharedRelros, | 396 waitForSharedRelros, |
398 linker.getTestRunnerClassNameForTest ing(), | 397 linker.getTestRunnerClassNameForTest ing(), |
399 linker.getImplementationForTesting() ); | 398 linker.getImplementationForTesting() ); |
400 } else { | 399 } else { |
401 return new ChromiumLinkerParams(sLinkerLoadAddress, | 400 return new ChromiumLinkerParams(sLinkerLoadAddress, |
402 waitForSharedRelros); | 401 waitForSharedRelros); |
403 } | 402 } |
404 } | 403 } |
405 | 404 |
406 private static ChildProcessConnection allocateBoundConnection(SpawnData spaw nData, | 405 private static ChildProcessConnection allocateBoundConnection( |
407 boolean alwaysInForeground, ChildProcessConnection.StartCallback sta rtCallback) { | 406 SpawnData spawnData, ChildProcessConnection.StartCallback startCallb ack) { |
408 final Context context = spawnData.context(); | 407 final Context context = spawnData.getContext(); |
409 final boolean inSandbox = spawnData.inSandbox(); | 408 final boolean inSandbox = spawnData.isInSandbox(); |
410 final ChildProcessCreationParams creationParams = spawnData.getCreationP arams(); | 409 final ChildProcessCreationParams creationParams = spawnData.getCreationP arams(); |
411 Bundle commonParams = new Bundle(); | 410 Bundle commonParams = new Bundle(); |
412 commonParams.putParcelable( | 411 commonParams.putParcelable( |
413 ChildProcessConstants.EXTRA_LINKER_PARAMS, getLinkerParamsForNew Connection()); | 412 ChildProcessConstants.EXTRA_LINKER_PARAMS, getLinkerParamsForNew Connection()); |
414 ChildProcessConnection connection = | 413 ChildProcessConnection connection = allocateConnection(spawnData, common Params); |
415 allocateConnection(spawnData, commonParams, alwaysInForeground); | |
416 if (connection != null) { | 414 if (connection != null) { |
417 connection.start(startCallback); | 415 connection.start(startCallback); |
418 | 416 |
419 String packageName = creationParams != null ? creationParams.getPack ageName() | 417 String packageName = creationParams != null ? creationParams.getPack ageName() |
420 : context.getPackageName (); | 418 : context.getPackageName (); |
421 if (inSandbox | 419 if (inSandbox |
422 && !getConnectionAllocator(packageName, inSandbox) | 420 && !getConnectionAllocator(packageName, inSandbox) |
423 .isFreeConnectionAvailable()) { | 421 .isFreeConnectionAvailable()) { |
424 // Proactively releases all the moderate bindings once all the s andboxed services | 422 // 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 | 423 // are allocated, which will be very likely to have some of them killed by OOM |
(...skipping 18 matching lines...) Expand all Loading... | |
444 // variables are set when we don't expect them to). | 442 // variables are set when we don't expect them to). |
445 final ChildProcessConnection conn = connection; | 443 final ChildProcessConnection conn = connection; |
446 ThreadUtils.postOnUiThreadDelayed(new Runnable() { | 444 ThreadUtils.postOnUiThreadDelayed(new Runnable() { |
447 @Override | 445 @Override |
448 public void run() { | 446 public void run() { |
449 final SpawnData pendingSpawn = freeConnectionAndDequeuePending(c onn); | 447 final SpawnData pendingSpawn = freeConnectionAndDequeuePending(c onn); |
450 if (pendingSpawn != null) { | 448 if (pendingSpawn != null) { |
451 LauncherThread.post(new Runnable() { | 449 LauncherThread.post(new Runnable() { |
452 @Override | 450 @Override |
453 public void run() { | 451 public void run() { |
454 startInternal(pendingSpawn.context(), pendingSpawn.c ommandLine(), | 452 startInternal(pendingSpawn.getContext(), pendingSpaw n.getCommandLine(), |
455 pendingSpawn.childProcessId(), pendingSpawn. filesToBeMapped(), | 453 pendingSpawn.getChildProcessId(), |
456 pendingSpawn.launchCallback(), pendingSpawn. callbackType(), | 454 pendingSpawn.getFilesToBeMapped(), |
457 pendingSpawn.inSandbox(), pendingSpawn.getCr eationParams()); | 455 pendingSpawn.getLaunchCallback(), |
456 pendingSpawn.getChildProcessCallback(), | |
457 pendingSpawn.isInSandbox(), pendingSpawn.isA lwaysInForeground(), | |
458 pendingSpawn.getCreationParams()); | |
458 } | 459 } |
459 }); | 460 }); |
460 } | 461 } |
461 } | 462 } |
462 }, FREE_CONNECTION_DELAY_MILLIS); | 463 }, FREE_CONNECTION_DELAY_MILLIS); |
463 } | 464 } |
464 | 465 |
465 private static SpawnData freeConnectionAndDequeuePending(ChildProcessConnect ion conn) { | 466 private static SpawnData freeConnectionAndDequeuePending(ChildProcessConnect ion conn) { |
466 ChildConnectionAllocator allocator = getConnectionAllocator( | 467 ChildConnectionAllocator allocator = getConnectionAllocator( |
467 conn.getPackageName(), conn.isInSandbox()); | 468 conn.getPackageName(), conn.isInSandbox()); |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
575 @Override | 576 @Override |
576 public void onChildStartFailed() { | 577 public void onChildStartFailed() { |
577 Log.e(TAG, "Failed to warm up the spare sandbox service"); | 578 Log.e(TAG, "Failed to warm up the spare sandbox service"); |
578 synchronized (sSpareConnectionLock) { | 579 synchronized (sSpareConnectionLock) { |
579 sSpareSandboxedConnection = null; | 580 sSpareSandboxedConnection = null; |
580 sSpareConnectionStarting = false; | 581 sSpareConnectionStarting = false; |
581 sSpareConnectionLock.notify(); | 582 sSpareConnectionLock.notify(); |
582 } | 583 } |
583 } | 584 } |
584 }; | 585 }; |
585 SpawnData spawnData = new SpawnData(true /* forWarmUp*/, context , | 586 SpawnData spawnData = |
586 null /* commandLine */, -1 /* child process id */, | 587 new SpawnData(true /* forWarmUp*/, context, null /* comm andLine */, |
587 null /* filesToBeMapped */, null /* launchCallback */, | 588 -1 /* child process id */, null /* filesToBeMapp ed */, |
588 CALLBACK_FOR_RENDERER_PROCESS, true /* inSandbox */, par ams); | 589 null /* launchCallback */, null /* child process callback */, |
589 sSpareSandboxedConnection = allocateBoundConnection( | 590 true /* inSandbox */, false /* alwaysInForegroun d */, params); |
590 spawnData, false /* alwaysInForeground */, startCallback ); | 591 sSpareSandboxedConnection = allocateBoundConnection(spawnData, s tartCallback); |
591 } | 592 } |
592 } | 593 } |
593 } | 594 } |
594 | 595 |
595 /** | 596 /** |
596 * Spawns and connects to a child process. May be called on any thread. It w ill not block, but | 597 * 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 | 598 * 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 | 599 * established. Note this callback will not necessarily be from the same thr ead (currently it |
599 * always comes from the main thread). | 600 * always comes from the main thread). |
600 * | 601 * |
601 * @param context Context used to obtain the application context. | 602 * @param context Context used to obtain the application context. |
602 * @param paramId Key used to retrieve ChildProcessCreationParams. | 603 * @param paramId Key used to retrieve ChildProcessCreationParams. |
603 * @param commandLine The child process command line argv. | 604 * @param commandLine The child process command line argv. |
604 * @param filesToBeMapped File IDs, FDs, offsets, and lengths to pass throug h. | 605 * @param filesToBeMapped File IDs, FDs, offsets, and lengths to pass throug h. |
605 */ | 606 */ |
606 // TODO(boliu): All tests should use this over startForTesting. | 607 // TODO(boliu): All tests should use this over startForTesting. |
607 static void start(Context context, int paramId, final String[] commandLine, int childProcessId, | 608 static void start(Context context, int paramId, final String[] commandLine, int childProcessId, |
608 FileDescriptorInfo[] filesToBeMapped, LaunchCallback launchCallback) { | 609 FileDescriptorInfo[] filesToBeMapped, LaunchCallback launchCallback) { |
609 int callbackType = CALLBACK_FOR_UNKNOWN_PROCESS; | 610 IBinder childProcessCallback = null; |
610 boolean inSandbox = true; | 611 boolean inSandbox = true; |
612 boolean alwaysInForeground = false; | |
611 String processType = | 613 String processType = |
612 ContentSwitches.getSwitchValue(commandLine, ContentSwitches.SWIT CH_PROCESS_TYPE); | 614 ContentSwitches.getSwitchValue(commandLine, ContentSwitches.SWIT CH_PROCESS_TYPE); |
613 ChildProcessCreationParams params = ChildProcessCreationParams.get(param Id); | 615 ChildProcessCreationParams params = ChildProcessCreationParams.get(param Id); |
614 if (paramId != ChildProcessCreationParams.DEFAULT_ID && params == null) { | 616 if (paramId != ChildProcessCreationParams.DEFAULT_ID && params == null) { |
615 throw new RuntimeException("CreationParams id " + paramId + " not fo und"); | 617 throw new RuntimeException("CreationParams id " + paramId + " not fo und"); |
616 } | 618 } |
617 if (ContentSwitches.SWITCH_RENDERER_PROCESS.equals(processType)) { | 619 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())) { | 620 if (params != null && !params.getPackageName().equals(context.getPac kageName())) { |
621 // WebViews and WebAPKs have renderer processes running in their applications. | 621 // WebViews and WebAPKs have renderer processes running in their applications. |
622 // When launching these renderer processes, {@link ChildProcessC onnectionImpl} | 622 // When launching these renderer processes, {@link ChildProcessC onnectionImpl} |
623 // requires the package name of the application which holds the renderer process. | 623 // requires the package name of the application which holds the renderer process. |
624 // Therefore, the package name in ChildProcessCreationParams cou ld be the package | 624 // Therefore, the package name in ChildProcessCreationParams cou ld be the package |
625 // name of WebViews, WebAPKs, or Chrome, depending on the host a pplication. | 625 // 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 | 626 // Except renderer process, all other child processes should use Chrome's package |
627 // name. In WebAPK, ChildProcessCreationParams are initialized w ith WebAPK's | 627 // 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 | 628 // 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. | 629 // Chrome's package to use when initializing a non-renderer proc esses. |
630 // TODO(boliu): Should fold into |paramId|. Investigate why this is needed. | 630 // TODO(boliu): Should fold into |paramId|. Investigate why this is needed. |
631 params = new ChildProcessCreationParams(context.getPackageName() , | 631 params = new ChildProcessCreationParams(context.getPackageName() , |
632 params.getIsExternalService(), params.getLibraryProcessT ype()); | 632 params.getIsExternalService(), params.getLibraryProcessT ype()); |
633 } | 633 } |
634 if (ContentSwitches.SWITCH_GPU_PROCESS.equals(processType)) { | 634 if (ContentSwitches.SWITCH_GPU_PROCESS.equals(processType)) { |
635 callbackType = CALLBACK_FOR_GPU_PROCESS; | 635 childProcessCallback = new GpuProcessCallback(); |
636 inSandbox = false; | 636 inSandbox = false; |
637 } else if (ContentSwitches.SWITCH_UTILITY_PROCESS.equals(processType )) { | 637 alwaysInForeground = true; |
638 // We only support sandboxed right now. | |
639 callbackType = CALLBACK_FOR_UTILITY_PROCESS; | |
640 } else { | 638 } else { |
641 assert false; | 639 // We only support sandboxed utility processes now. |
640 assert ContentSwitches.SWITCH_UTILITY_PROCESS.equals(processType ); | |
642 } | 641 } |
643 } | 642 } |
644 | 643 |
645 startInternal(context, commandLine, childProcessId, filesToBeMapped, lau nchCallback, | 644 startInternal(context, commandLine, childProcessId, filesToBeMapped, lau nchCallback, |
646 callbackType, inSandbox, params); | 645 childProcessCallback, inSandbox, alwaysInForeground, params); |
647 } | 646 } |
648 | 647 |
649 private static ChildProcessConnection startInternal(final Context context, | 648 private static ChildProcessConnection startInternal(final Context context, |
650 final String[] commandLine, final int childProcessId, | 649 final String[] commandLine, final int childProcessId, |
651 final FileDescriptorInfo[] filesToBeMapped, final LaunchCallback lau nchCallback, | 650 final FileDescriptorInfo[] filesToBeMapped, final LaunchCallback lau nchCallback, |
652 final int callbackType, final boolean inSandbox, | 651 final IBinder childProcessCallback, final boolean inSandbox, |
653 final ChildProcessCreationParams creationParams) { | 652 final boolean alwaysInForeground, final ChildProcessCreationParams c reationParams) { |
654 try { | 653 try { |
655 TraceEvent.begin("ChildProcessLauncher.startInternal"); | 654 TraceEvent.begin("ChildProcessLauncher.startInternal"); |
656 | 655 |
657 ChildProcessConnection allocatedConnection = null; | 656 ChildProcessConnection allocatedConnection = null; |
658 String packageName = creationParams != null ? creationParams.getPack ageName() | 657 String packageName = creationParams != null ? creationParams.getPack ageName() |
659 : context.getPackageName(); | 658 : context.getPackageName(); |
660 synchronized (sSpareConnectionLock) { | 659 synchronized (sSpareConnectionLock) { |
661 if (inSandbox && sSpareSandboxedConnection != null | 660 if (inSandbox && sSpareSandboxedConnection != null |
662 && sSpareSandboxedConnection.getPackageName().equals(pac kageName) | 661 && sSpareSandboxedConnection.getPackageName().equals(pac kageName) |
663 // Object identity check for getDefault should be enough . The default is | 662 // Object identity check for getDefault should be enough . The default is |
664 // not supposed to change once set. | 663 // not supposed to change once set. |
665 && creationParams == ChildProcessCreationParams.getDefau lt()) { | 664 && creationParams == ChildProcessCreationParams.getDefau lt()) { |
boliu
2017/04/04 15:57:18
should check here that alwaysInForeground matches
Jay Civelli
2017/04/04 16:26:35
Good catch, done.
| |
666 while (sSpareConnectionStarting) { | 665 while (sSpareConnectionStarting) { |
667 try { | 666 try { |
668 sSpareConnectionLock.wait(); | 667 sSpareConnectionLock.wait(); |
669 } catch (InterruptedException ex) { | 668 } catch (InterruptedException ex) { |
670 } | 669 } |
671 } | 670 } |
672 allocatedConnection = sSpareSandboxedConnection; | 671 allocatedConnection = sSpareSandboxedConnection; |
673 sSpareSandboxedConnection = null; | 672 sSpareSandboxedConnection = null; |
674 } | 673 } |
675 } | 674 } |
676 if (allocatedConnection == null) { | 675 if (allocatedConnection == null) { |
677 boolean alwaysInForeground = false; | |
678 if (callbackType == CALLBACK_FOR_GPU_PROCESS) alwaysInForeground = true; | |
679 ChildProcessConnection.StartCallback startCallback = | 676 ChildProcessConnection.StartCallback startCallback = |
680 new ChildProcessConnection.StartCallback() { | 677 new ChildProcessConnection.StartCallback() { |
681 @Override | 678 @Override |
682 public void onChildStarted() {} | 679 public void onChildStarted() {} |
683 | 680 |
684 @Override | 681 @Override |
685 public void onChildStartFailed() { | 682 public void onChildStartFailed() { |
686 Log.e(TAG, "ChildProcessConnection.start failed, trying again"); | 683 Log.e(TAG, "ChildProcessConnection.start failed, trying again"); |
687 LauncherThread.post(new Runnable() { | 684 LauncherThread.post(new Runnable() { |
688 @Override | 685 @Override |
689 public void run() { | 686 public void run() { |
690 // The child process may already be boun d to another client | 687 // The child process may already be boun d to another client |
691 // (this can happen if multi-process Web View is used in more | 688 // (this can happen if multi-process Web View is used in more |
692 // than one process), so try starting th e process again. | 689 // than one process), so try starting th e process again. |
693 // This connection that failed to start has not been freed, | 690 // This connection that failed to start has not been freed, |
694 // so a new bound connection will be all ocated. | 691 // so a new bound connection will be all ocated. |
695 startInternal(context, commandLine, chil dProcessId, | 692 startInternal(context, commandLine, chil dProcessId, |
696 filesToBeMapped, launchCallback, callbackType, | 693 filesToBeMapped, launchCallback, |
697 inSandbox, creationParams); | 694 childProcessCallback, inSandbox, alwaysInForeground, |
695 creationParams); | |
698 } | 696 } |
699 }); | 697 }); |
700 } | 698 } |
701 }; | 699 }; |
702 | 700 |
703 SpawnData spawnData = new SpawnData(false /* forWarmUp */, conte xt, commandLine, | 701 SpawnData spawnData = new SpawnData(false /* forWarmUp */, conte xt, commandLine, |
704 childProcessId, filesToBeMapped, launchCallback, callbac kType, inSandbox, | 702 childProcessId, filesToBeMapped, launchCallback, childPr ocessCallback, |
705 creationParams); | 703 inSandbox, alwaysInForeground, creationParams); |
706 allocatedConnection = | 704 allocatedConnection = allocateBoundConnection(spawnData, startCa llback); |
707 allocateBoundConnection(spawnData, alwaysInForeground, s tartCallback); | |
708 if (allocatedConnection == null) { | 705 if (allocatedConnection == null) { |
709 return null; | 706 return null; |
710 } | 707 } |
711 } | 708 } |
712 | 709 |
713 Log.d(TAG, "Setting up connection to process: slot=%d", | 710 Log.d(TAG, "Setting up connection to process: slot=%d", |
714 allocatedConnection.getServiceNumber()); | 711 allocatedConnection.getServiceNumber()); |
715 triggerConnectionSetup(allocatedConnection, commandLine, childProces sId, | 712 triggerConnectionSetup(allocatedConnection, commandLine, childProces sId, |
716 filesToBeMapped, callbackType, launchCallback); | 713 filesToBeMapped, childProcessCallback, launchCallback); |
717 return allocatedConnection; | 714 return allocatedConnection; |
718 } finally { | 715 } finally { |
719 TraceEvent.end("ChildProcessLauncher.startInternal"); | 716 TraceEvent.end("ChildProcessLauncher.startInternal"); |
720 } | 717 } |
721 } | 718 } |
722 | 719 |
723 /** | 720 /** |
724 * Create the common bundle to be passed to child processes. | 721 * Create the common bundle to be passed to child processes. |
725 * @param context Application context. | 722 * @param context Application context. |
726 * @param commandLine Command line params to be passed to the service. | 723 * @param commandLine Command line params to be passed to the service. |
727 * @param linkerParams Linker params to start the service. | 724 * @param linkerParams Linker params to start the service. |
728 */ | 725 */ |
729 protected static Bundle createsServiceBundle( | 726 protected static Bundle createsServiceBundle( |
730 String[] commandLine, FileDescriptorInfo[] filesToBeMapped) { | 727 String[] commandLine, FileDescriptorInfo[] filesToBeMapped) { |
731 Bundle bundle = new Bundle(); | 728 Bundle bundle = new Bundle(); |
732 bundle.putStringArray(ChildProcessConstants.EXTRA_COMMAND_LINE, commandL ine); | 729 bundle.putStringArray(ChildProcessConstants.EXTRA_COMMAND_LINE, commandL ine); |
733 bundle.putParcelableArray(ChildProcessConstants.EXTRA_FILES, filesToBeMa pped); | 730 bundle.putParcelableArray(ChildProcessConstants.EXTRA_FILES, filesToBeMa pped); |
734 bundle.putInt(ChildProcessConstants.EXTRA_CPU_COUNT, CpuFeatures.getCoun t()); | 731 bundle.putInt(ChildProcessConstants.EXTRA_CPU_COUNT, CpuFeatures.getCoun t()); |
735 bundle.putLong(ChildProcessConstants.EXTRA_CPU_FEATURES, CpuFeatures.get Mask()); | 732 bundle.putLong(ChildProcessConstants.EXTRA_CPU_FEATURES, CpuFeatures.get Mask()); |
736 bundle.putBundle(Linker.EXTRA_LINKER_SHARED_RELROS, Linker.getInstance() .getSharedRelros()); | 733 bundle.putBundle(Linker.EXTRA_LINKER_SHARED_RELROS, Linker.getInstance() .getSharedRelros()); |
737 return bundle; | 734 return bundle; |
738 } | 735 } |
739 | 736 |
740 @VisibleForTesting | 737 @VisibleForTesting |
741 static void triggerConnectionSetup(final ChildProcessConnection connection, | 738 static void triggerConnectionSetup(final ChildProcessConnection connection, |
742 String[] commandLine, int childProcessId, FileDescriptorInfo[] files ToBeMapped, | 739 String[] commandLine, int childProcessId, FileDescriptorInfo[] files ToBeMapped, |
743 final int callbackType, final LaunchCallback launchCallback) { | 740 final IBinder childProcessCallback, final LaunchCallback launchCallb ack) { |
744 ChildProcessConnection.ConnectionCallback connectionCallback = | 741 ChildProcessConnection.ConnectionCallback connectionCallback = |
745 new ChildProcessConnection.ConnectionCallback() { | 742 new ChildProcessConnection.ConnectionCallback() { |
746 @Override | 743 @Override |
747 public void onConnected(int pid) { | 744 public void onConnected(int pid) { |
748 Log.d(TAG, "on connect callback, pid=%d callbackType=%d" , pid, | 745 Log.d(TAG, "on connect callback, pid=%d", pid); |
749 callbackType); | |
750 if (pid != NULL_PROCESS_HANDLE) { | 746 if (pid != NULL_PROCESS_HANDLE) { |
751 sBindingManager.addNewConnection(pid, connection); | 747 sBindingManager.addNewConnection(pid, connection); |
752 sServiceMap.put(pid, connection); | 748 sServiceMap.put(pid, connection); |
753 } | 749 } |
754 // If the connection fails and pid == 0, the Java-side c leanup was already | 750 // 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 | 751 // handled by DeathCallback. We still have to call back to native for |
756 // cleanup there. | 752 // cleanup there. |
757 if (launchCallback != null) { // Will be null in Java in strumentation tests. | 753 if (launchCallback != null) { // Will be null in Java in strumentation tests. |
758 launchCallback.onChildProcessStarted(pid); | 754 launchCallback.onChildProcessStarted(pid); |
759 } | 755 } |
760 } | 756 } |
761 }; | 757 }; |
762 | 758 |
763 assert callbackType != CALLBACK_FOR_UNKNOWN_PROCESS; | 759 connection.setupConnection( |
764 connection.setupConnection(commandLine, filesToBeMapped, | 760 commandLine, filesToBeMapped, childProcessCallback, connectionCa llback); |
765 createCallback(childProcessId, callbackType), connectionCallback ); | |
766 } | 761 } |
767 | 762 |
768 /** | 763 /** |
769 * Terminates a child process. This may be called from any thread. | 764 * Terminates a child process. This may be called from any thread. |
770 * | 765 * |
771 * @param pid The pid (process handle) of the service connection obtained fr om {@link #start}. | 766 * @param pid The pid (process handle) of the service connection obtained fr om {@link #start}. |
772 */ | 767 */ |
773 static void stop(int pid) { | 768 static void stop(int pid) { |
774 Log.d(TAG, "stopping child connection: pid=%d", pid); | 769 Log.d(TAG, "stopping child connection: pid=%d", pid); |
775 ChildProcessConnection connection = sServiceMap.remove(pid); | 770 ChildProcessConnection connection = sServiceMap.remove(pid); |
776 if (connection == null) { | 771 if (connection == null) { |
777 // Can happen for single process. | 772 // Can happen for single process. |
778 return; | 773 return; |
779 } | 774 } |
780 sBindingManager.clearConnection(pid); | 775 sBindingManager.clearConnection(pid); |
781 connection.stop(); | 776 connection.stop(); |
782 freeConnection(connection); | 777 freeConnection(connection); |
783 } | 778 } |
784 | 779 |
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 | 780 @VisibleForTesting |
793 public static ChildProcessConnection startForTesting(Context context, String [] commandLine, | 781 public static ChildProcessConnection startForTesting(Context context, String [] commandLine, |
794 FileDescriptorInfo[] filesToMap, ChildProcessCreationParams params) { | 782 FileDescriptorInfo[] filesToMap, ChildProcessCreationParams params) { |
795 return startInternal(context, commandLine, 0, filesToMap, null, | 783 return startInternal(context, commandLine, 0 /* childProcessId */, files ToMap, |
796 CALLBACK_FOR_RENDERER_PROCESS, true, params); | 784 null /* launchCallback */, null /* childProcessCallback */, true /* inSandbox */, |
785 false /* alwaysInForeground */, params); | |
797 } | 786 } |
798 | 787 |
799 @VisibleForTesting | 788 @VisibleForTesting |
800 static ChildProcessConnection allocateBoundConnectionForTesting(Context cont ext, | 789 static ChildProcessConnection allocateBoundConnectionForTesting(Context cont ext, |
801 ChildProcessCreationParams creationParams) { | 790 ChildProcessCreationParams creationParams) { |
802 return allocateBoundConnection( | 791 return allocateBoundConnection( |
803 new SpawnData(false /* forWarmUp */, context, null /* commandLin e */, | 792 new SpawnData(false /* forWarmUp */, context, null /* commandLin e */, |
804 0 /* childProcessId */, null /* filesToBeMapped */, | 793 0 /* childProcessId */, null /* filesToBeMapped */, |
805 null /* LaunchCallback */, CALLBACK_FOR_RENDERER_PROCESS , | 794 null /* LaunchCallback */, null /* childProcessCallback */, |
806 true /* inSandbox */, creationParams), | 795 true /* inSandbox */, false /* alwaysInForeground */, cr eationParams), |
807 false /* alwaysInForeground */, null); | 796 null /* startCallback */); |
808 } | 797 } |
809 | 798 |
810 @VisibleForTesting | 799 @VisibleForTesting |
811 static ChildProcessConnection allocateConnectionForTesting(Context context, | 800 static ChildProcessConnection allocateConnectionForTesting(Context context, |
812 ChildProcessCreationParams creationParams) { | 801 ChildProcessCreationParams creationParams) { |
813 Bundle commonParams = new Bundle(); | 802 Bundle commonParams = new Bundle(); |
814 commonParams.putParcelable( | 803 commonParams.putParcelable( |
815 ChildProcessConstants.EXTRA_LINKER_PARAMS, getLinkerParamsForNew Connection()); | 804 ChildProcessConstants.EXTRA_LINKER_PARAMS, getLinkerParamsForNew Connection()); |
816 return allocateConnection( | 805 return allocateConnection( |
817 new SpawnData(false /* forWarmUp */, context, null /* commandLin e */, | 806 new SpawnData(false /* forWarmUp */, context, null /* commandLin e */, |
818 0 /* childProcessId */, null /* filesToBeMapped */, | 807 0 /* childProcessId */, null /* filesToBeMapped */, |
819 null /* LaunchCallback */, CALLBACK_FOR_RENDERER_PROCESS , | 808 null /* launchCallback */, null /* childProcessCallback */, |
820 true /* inSandbox */, creationParams), | 809 true /* inSandbox */, false /* alwaysInForeground */, cr eationParams), |
821 commonParams, false); | 810 commonParams); |
822 } | 811 } |
823 | 812 |
824 /** | 813 /** |
825 * Queue up a spawn requests for testing. | 814 * Queue up a spawn requests for testing. |
826 */ | 815 */ |
827 @VisibleForTesting | 816 @VisibleForTesting |
828 static void enqueuePendingSpawnForTesting(Context context, String[] commandL ine, | 817 static void enqueuePendingSpawnForTesting(Context context, String[] commandL ine, |
829 ChildProcessCreationParams creationParams, boolean inSandbox) { | 818 ChildProcessCreationParams creationParams, boolean inSandbox) { |
830 String packageName = creationParams != null ? creationParams.getPackageN ame() | 819 String packageName = creationParams != null ? creationParams.getPackageN ame() |
831 : context.getPackageName(); | 820 : context.getPackageName(); |
832 ChildConnectionAllocator allocator = | 821 ChildConnectionAllocator allocator = |
833 getAllocatorForTesting(context, packageName, inSandbox); | 822 getAllocatorForTesting(context, packageName, inSandbox); |
834 allocator.enqueuePendingQueueForTesting(new SpawnData(false /* forWarmUp */, context, | 823 allocator.enqueuePendingQueueForTesting(new SpawnData(false /* forWarmUp */, context, |
835 commandLine, 1, new FileDescriptorInfo[0], null, CALLBACK_FOR_RE NDERER_PROCESS, | 824 commandLine, 1 /* childProcessId */, new FileDescriptorInfo[0], |
836 true, creationParams)); | 825 null /* launchCallback */, null /* childProcessCallback */, true /* inSandbox */, |
826 false /* alwaysInForeground */, creationParams)); | |
837 } | 827 } |
838 | 828 |
839 /** | 829 /** |
840 * @return the number of sandboxed connections of given {@link packageName} managed by the | 830 * @return the number of sandboxed connections of given {@link packageName} managed by the |
841 * allocator. | 831 * allocator. |
842 */ | 832 */ |
843 @VisibleForTesting | 833 @VisibleForTesting |
844 static int allocatedSandboxedConnectionsCountForTesting(Context context, Str ing packageName) { | 834 static int allocatedSandboxedConnectionsCountForTesting(Context context, Str ing packageName) { |
845 initConnectionAllocatorsIfNecessary(context, true, packageName); | 835 initConnectionAllocatorsIfNecessary(context, true, packageName); |
846 return sSandboxedChildConnectionAllocatorMap.get(packageName) | 836 return sSandboxedChildConnectionAllocatorMap.get(packageName) |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
885 | 875 |
886 try { | 876 try { |
887 ((ChildProcessConnectionImpl) sServiceMap.get(pid)).crashServiceForT esting(); | 877 ((ChildProcessConnectionImpl) sServiceMap.get(pid)).crashServiceForT esting(); |
888 } catch (RemoteException ex) { | 878 } catch (RemoteException ex) { |
889 return false; | 879 return false; |
890 } | 880 } |
891 | 881 |
892 return true; | 882 return true; |
893 } | 883 } |
894 } | 884 } |
OLD | NEW |