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 |