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; |
| 11 import android.os.AsyncTask; | |
| 11 import android.os.Bundle; | 12 import android.os.Bundle; |
| 12 import android.os.ParcelFileDescriptor; | 13 import android.os.ParcelFileDescriptor; |
| 13 import android.os.RemoteException; | 14 import android.os.RemoteException; |
| 14 import android.text.TextUtils; | 15 import android.text.TextUtils; |
| 15 import android.view.Surface; | 16 import android.view.Surface; |
| 16 | 17 |
| 17 import org.chromium.base.CommandLine; | 18 import org.chromium.base.CommandLine; |
| 18 import org.chromium.base.CpuFeatures; | 19 import org.chromium.base.CpuFeatures; |
| 19 import org.chromium.base.Log; | 20 import org.chromium.base.Log; |
| 20 import org.chromium.base.ThreadUtils; | 21 import org.chromium.base.ThreadUtils; |
| (...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 406 linker.getTestRunnerClassNameForTest ing(), | 407 linker.getTestRunnerClassNameForTest ing(), |
| 407 linker.getImplementationForTesting() ); | 408 linker.getImplementationForTesting() ); |
| 408 } else { | 409 } else { |
| 409 return new ChromiumLinkerParams(sLinkerLoadAddress, | 410 return new ChromiumLinkerParams(sLinkerLoadAddress, |
| 410 waitForSharedRelros); | 411 waitForSharedRelros); |
| 411 } | 412 } |
| 412 } | 413 } |
| 413 | 414 |
| 414 private static ChildProcessConnection allocateBoundConnection(Context contex t, | 415 private static ChildProcessConnection allocateBoundConnection(Context contex t, |
| 415 String[] commandLine, boolean inSandbox, boolean alwaysInForeground, | 416 String[] commandLine, boolean inSandbox, boolean alwaysInForeground, |
| 416 ChildProcessCreationParams creationParams) { | 417 ChildProcessCreationParams creationParams, |
| 418 ChildProcessConnection.StartCallback startCallback) { | |
| 417 ChromiumLinkerParams chromiumLinkerParams = getLinkerParamsForNewConnect ion(); | 419 ChromiumLinkerParams chromiumLinkerParams = getLinkerParamsForNewConnect ion(); |
| 418 ChildProcessConnection connection = allocateConnection( | 420 ChildProcessConnection connection = allocateConnection( |
| 419 context, inSandbox, chromiumLinkerParams, alwaysInForeground, cr eationParams); | 421 context, inSandbox, chromiumLinkerParams, alwaysInForeground, cr eationParams); |
| 420 if (connection != null) { | 422 if (connection != null) { |
| 421 connection.start(commandLine); | 423 connection.start(commandLine, startCallback); |
| 422 | 424 |
| 423 String packageName = creationParams != null ? creationParams.getPack ageName() | 425 String packageName = creationParams != null ? creationParams.getPack ageName() |
| 424 : context.getPackageName(); | 426 : context.getPackageName(); |
| 425 if (inSandbox && !getConnectionAllocator(packageName, inSandbox) | 427 if (inSandbox && !getConnectionAllocator(packageName, inSandbox) |
| 426 .isFreeConnectionAvailable()) { | 428 .isFreeConnectionAvailable()) { |
| 427 // Proactively releases all the moderate bindings once all the s andboxed services | 429 // Proactively releases all the moderate bindings once all the s andboxed services |
| 428 // are allocated, which will be very likely to have some of them killed by OOM | 430 // are allocated, which will be very likely to have some of them killed by OOM |
| 429 // killer. | 431 // killer. |
| 430 sBindingManager.releaseAllModerateBindings(); | 432 sBindingManager.releaseAllModerateBindings(); |
| 431 } | 433 } |
| 432 } | 434 } |
| 433 return connection; | 435 return connection; |
| 434 } | 436 } |
| 435 | 437 |
| 436 private static final long FREE_CONNECTION_DELAY_MILLIS = 1; | 438 private static final long FREE_CONNECTION_DELAY_MILLIS = 1; |
| 437 | 439 |
| 438 private static void freeConnection(ChildProcessConnection connection) { | 440 private static void freeConnection(ChildProcessConnection connection) { |
| 439 synchronized (ChildProcessLauncher.class) { | 441 synchronized (sSpareConnectionLock) { |
| 440 if (connection.equals(sSpareSandboxedConnection)) sSpareSandboxedCon nection = null; | 442 if (connection.equals(sSpareSandboxedConnection)) sSpareSandboxedCon nection = null; |
| 441 } | 443 } |
| 442 | 444 |
| 443 // Freeing a service should be delayed. This is so that we avoid immedia tely reusing the | 445 // Freeing a service should be delayed. This is so that we avoid immedia tely reusing the |
| 444 // freed service (see http://crbug.com/164069): the framework might keep a service process | 446 // freed service (see http://crbug.com/164069): the framework might keep a service process |
| 445 // alive when it's been unbound for a short time. If a new connection to the same service | 447 // alive when it's been unbound for a short time. If a new connection to the same service |
| 446 // is bound at that point, the process is reused and bad things happen ( mostly static | 448 // is bound at that point, the process is reused and bad things happen ( mostly static |
| 447 // variables are set when we don't expect them to). | 449 // variables are set when we don't expect them to). |
| 448 final ChildProcessConnection conn = connection; | 450 final ChildProcessConnection conn = connection; |
| 449 ThreadUtils.postOnUiThreadDelayed(new Runnable() { | 451 ThreadUtils.postOnUiThreadDelayed(new Runnable() { |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 476 } | 478 } |
| 477 } | 479 } |
| 478 | 480 |
| 479 // Represents an invalid process handle; same as base/process/process.h kNul lProcessHandle. | 481 // Represents an invalid process handle; same as base/process/process.h kNul lProcessHandle. |
| 480 private static final int NULL_PROCESS_HANDLE = 0; | 482 private static final int NULL_PROCESS_HANDLE = 0; |
| 481 | 483 |
| 482 // Map from pid to ChildService connection. | 484 // Map from pid to ChildService connection. |
| 483 private static Map<Integer, ChildProcessConnection> sServiceMap = | 485 private static Map<Integer, ChildProcessConnection> sServiceMap = |
| 484 new ConcurrentHashMap<Integer, ChildProcessConnection>(); | 486 new ConcurrentHashMap<Integer, ChildProcessConnection>(); |
| 485 | 487 |
| 488 // Lock and monitor for these members {{{ | |
| 489 private static final Object sSpareConnectionLock = new Object(); | |
| 486 // A pre-allocated and pre-bound connection ready for connection setup, or n ull. | 490 // A pre-allocated and pre-bound connection ready for connection setup, or n ull. |
| 487 private static ChildProcessConnection sSpareSandboxedConnection; | 491 private static ChildProcessConnection sSpareSandboxedConnection; |
| 492 // If sSpareSandboxedConnection is not null, this indicates whether the serv ice is | |
| 493 // ready for connection setup. Wait on the monitor lock to be notified when this | |
| 494 // state changes. sSpareSandboxedConnection may be null after waiting, if st arting | |
| 495 // the service failed. | |
| 496 private static boolean sSpareConnectionStarting; | |
| 497 // }}} | |
| 488 | 498 |
| 489 // Manages oom bindings used to bind chind services. | 499 // Manages oom bindings used to bind chind services. |
| 490 private static BindingManager sBindingManager = BindingManagerImpl.createBin dingManager(); | 500 private static BindingManager sBindingManager = BindingManagerImpl.createBin dingManager(); |
| 491 | 501 |
| 492 // Whether the main application is currently brought to the foreground. | 502 // Whether the main application is currently brought to the foreground. |
| 493 private static boolean sApplicationInForeground = true; | 503 private static boolean sApplicationInForeground = true; |
| 494 | 504 |
| 495 @VisibleForTesting | 505 @VisibleForTesting |
| 496 public static void setBindingManagerForTesting(BindingManager manager) { | 506 public static void setBindingManagerForTesting(BindingManager manager) { |
| 497 sBindingManager = manager; | 507 sBindingManager = manager; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 560 return sApplicationInForeground; | 570 return sApplicationInForeground; |
| 561 } | 571 } |
| 562 | 572 |
| 563 /** | 573 /** |
| 564 * Should be called early in startup so the work needed to spawn the child p rocess can be done | 574 * Should be called early in startup so the work needed to spawn the child p rocess can be done |
| 565 * in parallel to other startup work. Must not be called on the UI thread. S pare connection is | 575 * in parallel to other startup work. Must not be called on the UI thread. S pare connection is |
| 566 * created in sandboxed child process. | 576 * created in sandboxed child process. |
| 567 * @param context the application context used for the connection. | 577 * @param context the application context used for the connection. |
| 568 */ | 578 */ |
| 569 public static void warmUp(Context context) { | 579 public static void warmUp(Context context) { |
| 570 synchronized (ChildProcessLauncher.class) { | 580 synchronized (sSpareConnectionLock) { |
| 571 assert !ThreadUtils.runningOnUiThread(); | 581 assert !ThreadUtils.runningOnUiThread(); |
| 572 if (sSpareSandboxedConnection == null) { | 582 if (sSpareSandboxedConnection == null) { |
| 573 ChildProcessCreationParams params = ChildProcessCreationParams.g et(); | 583 ChildProcessCreationParams params = ChildProcessCreationParams.g et(); |
| 574 if (params != null) { | 584 if (params != null) { |
| 575 params = params.copy(); | 585 params = params.copy(); |
| 576 } | 586 } |
| 587 | |
|
Tobias Sargeant
2017/01/14 23:24:58
Presumably the fact that warmUp doesn't retry mean
Robert Sesek
2017/01/17 19:51:22
Since warmUp is only used for the first connection
| |
| 588 sSpareConnectionStarting = true; | |
| 589 | |
| 590 ChildProcessConnection.StartCallback startCallback = | |
| 591 new ChildProcessConnection.StartCallback() { | |
| 592 @Override | |
| 593 public void onChildStarted() { | |
| 594 synchronized (sSpareConnectionLock) { | |
| 595 sSpareConnectionStarting = false; | |
| 596 sSpareConnectionLock.notify(); | |
| 597 } | |
| 598 } | |
| 599 | |
| 600 @Override | |
| 601 public void onChildStartFailed() { | |
| 602 Log.e(TAG, "Failed to warm up the spare sandbox service"); | |
| 603 synchronized (sSpareConnectionLock) { | |
| 604 sSpareSandboxedConnection = null; | |
| 605 sSpareConnectionStarting = false; | |
| 606 sSpareConnectionLock.notify(); | |
| 607 } | |
| 608 } | |
| 609 }; | |
| 577 sSpareSandboxedConnection = allocateBoundConnection(context, nul l, true, false, | 610 sSpareSandboxedConnection = allocateBoundConnection(context, nul l, true, false, |
| 578 params); | 611 params, startCallback); |
| 579 } | 612 } |
| 580 } | 613 } |
| 581 } | 614 } |
| 582 | 615 |
| 583 @CalledByNative | 616 @CalledByNative |
| 584 private static FileDescriptorInfo makeFdInfo( | 617 private static FileDescriptorInfo makeFdInfo( |
| 585 int id, int fd, boolean autoClose, long offset, long size) { | 618 int id, int fd, boolean autoClose, long offset, long size) { |
| 586 ParcelFileDescriptor pFd; | 619 ParcelFileDescriptor pFd; |
| 587 if (autoClose) { | 620 if (autoClose) { |
| 588 // Adopt the FD, it will be closed when we close the ParcelFileDescr iptor. | 621 // Adopt the FD, it will be closed when we close the ParcelFileDescr iptor. |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 647 } else { | 680 } else { |
| 648 assert false; | 681 assert false; |
| 649 } | 682 } |
| 650 } | 683 } |
| 651 | 684 |
| 652 startInternal(context, commandLine, childProcessId, filesToBeMapped, cli entContext, | 685 startInternal(context, commandLine, childProcessId, filesToBeMapped, cli entContext, |
| 653 callbackType, inSandbox, params); | 686 callbackType, inSandbox, params); |
| 654 } | 687 } |
| 655 | 688 |
| 656 private static void startInternal( | 689 private static void startInternal( |
| 657 Context context, | 690 final Context context, |
| 658 final String[] commandLine, | 691 final String[] commandLine, |
| 659 int childProcessId, | 692 final int childProcessId, |
| 660 FileDescriptorInfo[] filesToBeMapped, | 693 final FileDescriptorInfo[] filesToBeMapped, |
| 661 long clientContext, | 694 final long clientContext, |
| 662 int callbackType, | 695 final int callbackType, |
| 663 boolean inSandbox, | 696 final boolean inSandbox, |
| 664 ChildProcessCreationParams creationParams) { | 697 final ChildProcessCreationParams creationParams) { |
| 665 try { | 698 try { |
| 666 TraceEvent.begin("ChildProcessLauncher.startInternal"); | 699 TraceEvent.begin("ChildProcessLauncher.startInternal"); |
| 667 | 700 |
| 668 ChildProcessConnection allocatedConnection = null; | 701 ChildProcessConnection allocatedConnection = null; |
| 669 String packageName = creationParams != null ? creationParams.getPack ageName() | 702 String packageName = creationParams != null ? creationParams.getPack ageName() |
| 670 : context.getPackageName(); | 703 : context.getPackageName(); |
| 671 synchronized (ChildProcessLauncher.class) { | 704 synchronized (sSpareConnectionLock) { |
| 672 if (inSandbox && sSpareSandboxedConnection != null | 705 if (inSandbox && sSpareSandboxedConnection != null |
| 673 && sSpareSandboxedConnection.getPackageName().equals(pac kageName)) { | 706 && sSpareSandboxedConnection.getPackageName().equals(pac kageName)) { |
| 707 while (sSpareConnectionStarting) { | |
| 708 try { | |
| 709 sSpareConnectionLock.wait(); | |
| 710 } catch (InterruptedException ex) { | |
| 711 } | |
| 712 } | |
| 674 allocatedConnection = sSpareSandboxedConnection; | 713 allocatedConnection = sSpareSandboxedConnection; |
| 675 sSpareSandboxedConnection = null; | 714 sSpareSandboxedConnection = null; |
| 676 } | 715 } |
| 677 } | 716 } |
| 678 if (allocatedConnection == null) { | 717 if (allocatedConnection == null) { |
| 679 boolean alwaysInForeground = false; | 718 boolean alwaysInForeground = false; |
| 680 if (callbackType == CALLBACK_FOR_GPU_PROCESS) alwaysInForeground = true; | 719 if (callbackType == CALLBACK_FOR_GPU_PROCESS) alwaysInForeground = true; |
| 681 PendingSpawnQueue pendingSpawnQueue = getPendingSpawnQueue( | 720 PendingSpawnQueue pendingSpawnQueue = getPendingSpawnQueue( |
| 682 context, packageName, inSandbox); | 721 context, packageName, inSandbox); |
| 722 ChildProcessConnection.StartCallback startCallback = | |
| 723 new ChildProcessConnection.StartCallback() { | |
| 724 @Override | |
| 725 public void onChildStarted() {} | |
| 726 | |
| 727 @Override | |
| 728 public void onChildStartFailed() { | |
| 729 Log.e(TAG, "ChildProcessConnection.start failed, trying again"); | |
| 730 new AsyncTask<Void, Void, Void>() { | |
|
Torne
2017/01/16 12:44:43
If the asynctask only has a doInBackground and is
Robert Sesek
2017/01/17 19:51:22
Done.
| |
| 731 @Override | |
| 732 protected Void doInBackground(Void... params ) { | |
| 733 startInternal(context, commandLine, chil dProcessId, | |
| 734 filesToBeMapped, clientContext, callbackType, | |
| 735 inSandbox, creationParams); | |
| 736 return null; | |
| 737 } | |
| 738 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUT OR); | |
| 739 } | |
| 740 }; | |
| 683 synchronized (pendingSpawnQueue.mPendingSpawnsLock) { | 741 synchronized (pendingSpawnQueue.mPendingSpawnsLock) { |
| 684 allocatedConnection = allocateBoundConnection( | 742 allocatedConnection = allocateBoundConnection( |
| 685 context, commandLine, inSandbox, alwaysInForeground, creationParams); | 743 context, commandLine, inSandbox, alwaysInForeground, creationParams, |
| 744 startCallback); | |
| 686 if (allocatedConnection == null) { | 745 if (allocatedConnection == null) { |
| 687 Log.d(TAG, "Allocation of new service failed. Queuing up pending spawn."); | 746 Log.d(TAG, "Allocation of new service failed. Queuing up pending spawn."); |
| 688 pendingSpawnQueue.enqueueLocked(new PendingSpawnData(con text, commandLine, | 747 pendingSpawnQueue.enqueueLocked(new PendingSpawnData(con text, commandLine, |
| 689 childProcessId, filesToBeMapped, clientContext, | 748 childProcessId, filesToBeMapped, clientContext, |
| 690 callbackType, inSandbox, creationParams)); | 749 callbackType, inSandbox, creationParams)); |
| 691 return; | 750 return; |
| 692 } | 751 } |
| 693 } | 752 } |
| 694 } | 753 } |
| 695 | 754 |
| 696 Log.d(TAG, "Setting up connection to process: slot=%d", | 755 Log.d(TAG, "Setting up connection to process: slot=%d", |
| 697 allocatedConnection.getServiceNumber()); | 756 allocatedConnection.getServiceNumber()); |
| 698 triggerConnectionSetup(allocatedConnection, commandLine, childProces sId, | 757 triggerConnectionSetup(allocatedConnection, commandLine, childProces sId, |
|
Tobias Sargeant
2017/01/14 23:24:57
I'm not sure that I understand this code, but in t
Torne
2017/01/16 12:44:43
I think it will have early returned on line 750 ab
Robert Sesek
2017/01/17 19:51:22
Right. allocatedConnection will be null so it will
| |
| 699 filesToBeMapped, callbackType, clientContext); | 758 filesToBeMapped, callbackType, clientContext); |
| 700 } finally { | 759 } finally { |
| 701 TraceEvent.end("ChildProcessLauncher.startInternal"); | 760 TraceEvent.end("ChildProcessLauncher.startInternal"); |
| 702 } | 761 } |
| 703 } | 762 } |
| 704 | 763 |
| 705 /** | 764 /** |
| 706 * Create the common bundle to be passed to child processes. | 765 * Create the common bundle to be passed to child processes. |
| 707 * @param context Application context. | 766 * @param context Application context. |
| 708 * @param commandLine Command line params to be passed to the service. | 767 * @param commandLine Command line params to be passed to the service. |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 829 static void logPidWarning(int pid, String message) { | 888 static void logPidWarning(int pid, String message) { |
| 830 // This class is effectively a no-op in single process mode, so don't lo g warnings there. | 889 // This class is effectively a no-op in single process mode, so don't lo g warnings there. |
| 831 if (pid > 0 && !nativeIsSingleProcess()) { | 890 if (pid > 0 && !nativeIsSingleProcess()) { |
| 832 Log.w(TAG, "%s, pid=%d", message, pid); | 891 Log.w(TAG, "%s, pid=%d", message, pid); |
| 833 } | 892 } |
| 834 } | 893 } |
| 835 | 894 |
| 836 @VisibleForTesting | 895 @VisibleForTesting |
| 837 static ChildProcessConnection allocateBoundConnectionForTesting(Context cont ext, | 896 static ChildProcessConnection allocateBoundConnectionForTesting(Context cont ext, |
| 838 ChildProcessCreationParams creationParams) { | 897 ChildProcessCreationParams creationParams) { |
| 839 return allocateBoundConnection(context, null, true, false, creationParam s); | 898 return allocateBoundConnection(context, null, true, false, creationParam s, null); |
| 840 } | 899 } |
| 841 | 900 |
| 842 @VisibleForTesting | 901 @VisibleForTesting |
| 843 static ChildProcessConnection allocateConnectionForTesting(Context context, | 902 static ChildProcessConnection allocateConnectionForTesting(Context context, |
| 844 ChildProcessCreationParams creationParams) { | 903 ChildProcessCreationParams creationParams) { |
| 845 return allocateConnection( | 904 return allocateConnection( |
| 846 context, true, getLinkerParamsForNewConnection(), false, creatio nParams); | 905 context, true, getLinkerParamsForNewConnection(), false, creatio nParams); |
| 847 } | 906 } |
| 848 | 907 |
| 849 /** | 908 /** |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 913 } | 972 } |
| 914 | 973 |
| 915 private static native void nativeOnChildProcessStarted(long clientContext, i nt pid); | 974 private static native void nativeOnChildProcessStarted(long clientContext, i nt pid); |
| 916 private static native void nativeEstablishSurfacePeer( | 975 private static native void nativeEstablishSurfacePeer( |
| 917 int pid, Surface surface, int primaryID, int secondaryID); | 976 int pid, Surface surface, int primaryID, int secondaryID); |
| 918 private static native void nativeCompleteScopedSurfaceRequest( | 977 private static native void nativeCompleteScopedSurfaceRequest( |
| 919 UnguessableToken requestToken, Surface surface); | 978 UnguessableToken requestToken, Surface surface); |
| 920 private static native boolean nativeIsSingleProcess(); | 979 private static native boolean nativeIsSingleProcess(); |
| 921 private static native Surface nativeGetViewSurface(int surfaceId); | 980 private static native Surface nativeGetViewSurface(int surfaceId); |
| 922 } | 981 } |
| OLD | NEW |