Index: content/public/android/java/src/org/chromium/content/browser/BaseChildProcessConnection.java |
diff --git a/content/public/android/java/src/org/chromium/content/browser/BaseChildProcessConnection.java b/content/public/android/java/src/org/chromium/content/browser/BaseChildProcessConnection.java |
index 52bfe5e5a7876a9868afff7493a07b436c6e7a19..c719dd774b3d196b6de36af09120c6708c3e5978 100644 |
--- a/content/public/android/java/src/org/chromium/content/browser/BaseChildProcessConnection.java |
+++ b/content/public/android/java/src/org/chromium/content/browser/BaseChildProcessConnection.java |
@@ -26,7 +26,6 @@ import org.chromium.base.process_launcher.IChildProcessService; |
import java.io.IOException; |
import javax.annotation.Nullable; |
-import javax.annotation.concurrent.GuardedBy; |
/** |
* Manages a connection between the browser activity and a child service. |
@@ -188,52 +187,39 @@ public abstract class BaseChildProcessConnection { |
} |
} |
- // Synchronization: While most internal flow occurs on the UI thread, the public API |
- // (specifically start and stop) may be called from any thread, hence all entry point methods |
- // into the class are synchronized on the lock to protect access to these members. |
- // TODO(jcivelli): crbug.com/714657 remove this lock. |
- private final Object mLock = new Object(); |
- |
// This is set in start() and is used in onServiceConnected(). |
- @GuardedBy("mLock") |
private StartCallback mStartCallback; |
// This is set in setupConnection() and is later used in doConnectionSetupLocked(), after which |
// the variable is cleared. Therefore this is only valid while the connection is being set up. |
- @GuardedBy("mLock") |
private ConnectionParams mConnectionParams; |
// Callback provided in setupConnection() that will communicate the result to the caller. This |
// has to be called exactly once after setupConnection(), even if setup fails, so that the |
// caller can free up resources associated with the setup attempt. This is set to null after the |
// call. |
- @GuardedBy("mLock") |
private ConnectionCallback mConnectionCallback; |
- @GuardedBy("mLock") |
private IChildProcessService mService; |
// Set to true when the service connection callback runs. This differs from |
// mServiceConnectComplete, which tracks that the connection completed successfully. |
- @GuardedBy("mLock") |
private boolean mDidOnServiceConnected; |
// Set to true when the service connected successfully. |
- @GuardedBy("mLock") |
private boolean mServiceConnectComplete; |
// Set to true when the service disconnects, as opposed to being properly closed. This happens |
// when the process crashes or gets killed by the system out-of-memory killer. |
- @GuardedBy("mLock") |
private boolean mServiceDisconnected; |
// Process ID of the corresponding child process. |
- @GuardedBy("mLock") |
private int mPid; |
protected BaseChildProcessConnection(Context context, int number, boolean sandboxed, |
DeathCallback deathCallback, String serviceClassName, |
Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams) { |
+ assert LauncherThread.runningOnLauncherThread(); |
mContext = context; |
mServiceNumber = number; |
mSandboxed = sandboxed; |
@@ -246,33 +232,38 @@ public abstract class BaseChildProcessConnection { |
} |
public final Context getContext() { |
+ assert LauncherThread.runningOnLauncherThread(); |
return mContext; |
} |
public final int getServiceNumber() { |
+ assert LauncherThread.runningOnLauncherThread(); |
return mServiceNumber; |
} |
public final boolean isSandboxed() { |
+ assert LauncherThread.runningOnLauncherThread(); |
return mSandboxed; |
} |
public final String getPackageName() { |
+ assert LauncherThread.runningOnLauncherThread(); |
return mCreationParams != null ? mCreationParams.getPackageName() |
: mContext.getPackageName(); |
} |
public final ChildProcessCreationParams getCreationParams() { |
+ assert LauncherThread.runningOnLauncherThread(); |
return mCreationParams; |
} |
public final IChildProcessService getService() { |
- synchronized (mLock) { |
- return mService; |
- } |
+ assert LauncherThread.runningOnLauncherThread(); |
+ return mService; |
} |
public final ComponentName getServiceName() { |
+ assert LauncherThread.runningOnLauncherThread(); |
return mServiceName; |
} |
@@ -280,9 +271,8 @@ public abstract class BaseChildProcessConnection { |
* @return the connection pid, or 0 if not yet connected |
*/ |
public int getPid() { |
- synchronized (mLock) { |
- return mPid; |
- } |
+ assert LauncherThread.runningOnLauncherThread(); |
+ return mPid; |
} |
/** |
@@ -293,22 +283,21 @@ public abstract class BaseChildProcessConnection { |
* @param startCallback (optional) callback when the child process starts or fails to start. |
*/ |
public void start(StartCallback startCallback) { |
+ assert LauncherThread.runningOnLauncherThread(); |
try { |
TraceEvent.begin("BaseChildProcessConnection.start"); |
assert LauncherThread.runningOnLauncherThread(); |
- synchronized (mLock) { |
- assert mConnectionParams |
- == null |
- : "setupConnection() called before start() in BaseChildProcessConnection."; |
- |
- mStartCallback = startCallback; |
- |
- if (!bind()) { |
- Log.e(TAG, "Failed to establish the service connection."); |
- // We have to notify the caller so that they can free-up associated resources. |
- // TODO(ppi): Can we hard-fail here? |
- mDeathCallback.onChildProcessDied(BaseChildProcessConnection.this); |
- } |
+ assert mConnectionParams |
+ == null |
+ : "setupConnection() called before start() in BaseChildProcessConnection."; |
+ |
+ mStartCallback = startCallback; |
+ |
+ if (!bind()) { |
+ Log.e(TAG, "Failed to establish the service connection."); |
+ // We have to notify the caller so that they can free-up associated resources. |
+ // TODO(ppi): Can we hard-fail here? |
+ mDeathCallback.onChildProcessDied(BaseChildProcessConnection.this); |
} |
} finally { |
TraceEvent.end("BaseChildProcessConnection.start"); |
@@ -327,25 +316,23 @@ public abstract class BaseChildProcessConnection { |
public void setupConnection(String[] commandLine, FileDescriptorInfo[] filesToBeMapped, |
@Nullable IBinder callback, ConnectionCallback connectionCallback) { |
assert LauncherThread.runningOnLauncherThread(); |
- synchronized (mLock) { |
- assert mConnectionParams == null; |
- if (mServiceDisconnected) { |
- Log.w(TAG, "Tried to setup a connection that already disconnected."); |
- connectionCallback.onConnected(null); |
- return; |
- } |
- try { |
- TraceEvent.begin("BaseChildProcessConnection.setupConnection"); |
- mConnectionCallback = connectionCallback; |
- mConnectionParams = new ConnectionParams(commandLine, filesToBeMapped, callback); |
- // Run the setup if the service is already connected. If not, |
- // doConnectionSetupLocked() will be called from onServiceConnected(). |
- if (mServiceConnectComplete) { |
- doConnectionSetupLocked(); |
- } |
- } finally { |
- TraceEvent.end("BaseChildProcessConnection.setupConnection"); |
+ assert mConnectionParams == null; |
+ if (mServiceDisconnected) { |
+ Log.w(TAG, "Tried to setup a connection that already disconnected."); |
+ connectionCallback.onConnected(null); |
+ return; |
+ } |
+ try { |
+ TraceEvent.begin("BaseChildProcessConnection.setupConnection"); |
+ mConnectionCallback = connectionCallback; |
+ mConnectionParams = new ConnectionParams(commandLine, filesToBeMapped, callback); |
+ // Run the setup if the service is already connected. If not, |
+ // doConnectionSetupLocked() will be called from onServiceConnected(). |
+ if (mServiceConnectComplete) { |
+ doConnectionSetupLocked(); |
} |
+ } finally { |
+ TraceEvent.end("BaseChildProcessConnection.setupConnection"); |
} |
} |
@@ -354,99 +341,91 @@ public abstract class BaseChildProcessConnection { |
* this multiple times. |
*/ |
public void stop() { |
- synchronized (mLock) { |
- unbind(); |
- mService = null; |
- mConnectionParams = null; |
- } |
+ assert LauncherThread.runningOnLauncherThread(); |
+ unbind(); |
+ mService = null; |
+ mConnectionParams = null; |
} |
private void onServiceConnectedOnLauncherThread(IBinder service) { |
assert LauncherThread.runningOnLauncherThread(); |
- synchronized (mLock) { |
- // A flag from the parent class ensures we run the post-connection logic only once |
- // (instead of once per each ChildServiceConnection). |
- if (mDidOnServiceConnected) { |
- return; |
- } |
- try { |
- TraceEvent.begin( |
- "BaseChildProcessConnection.ChildServiceConnection.onServiceConnected"); |
- mDidOnServiceConnected = true; |
- mService = IChildProcessService.Stub.asInterface(service); |
+ // A flag from the parent class ensures we run the post-connection logic only once |
+ // (instead of once per each ChildServiceConnection). |
+ if (mDidOnServiceConnected) { |
+ return; |
+ } |
+ try { |
+ TraceEvent.begin( |
+ "BaseChildProcessConnection.ChildServiceConnection.onServiceConnected"); |
+ mDidOnServiceConnected = true; |
+ mService = IChildProcessService.Stub.asInterface(service); |
- StartCallback startCallback = mStartCallback; |
- mStartCallback = null; |
+ StartCallback startCallback = mStartCallback; |
+ mStartCallback = null; |
- final boolean bindCheck = |
- mCreationParams != null && mCreationParams.getBindToCallerCheck(); |
- boolean boundToUs = false; |
- try { |
- boundToUs = bindCheck ? mService.bindToCaller() : true; |
- } catch (RemoteException ex) { |
- // Do not trigger the StartCallback here, since the service is already |
- // dead and the DeathCallback will run from onServiceDisconnected(). |
- Log.e(TAG, "Failed to bind service to connection.", ex); |
- return; |
- } |
+ final boolean bindCheck = |
+ mCreationParams != null && mCreationParams.getBindToCallerCheck(); |
+ boolean boundToUs = false; |
+ try { |
+ boundToUs = bindCheck ? mService.bindToCaller() : true; |
+ } catch (RemoteException ex) { |
+ // Do not trigger the StartCallback here, since the service is already |
+ // dead and the DeathCallback will run from onServiceDisconnected(). |
+ Log.e(TAG, "Failed to bind service to connection.", ex); |
+ return; |
+ } |
- if (startCallback != null) { |
- if (boundToUs) { |
- startCallback.onChildStarted(); |
- } else { |
- startCallback.onChildStartFailed(); |
- } |
+ if (startCallback != null) { |
+ if (boundToUs) { |
+ startCallback.onChildStarted(); |
+ } else { |
+ startCallback.onChildStartFailed(); |
} |
+ } |
- if (!boundToUs) { |
- return; |
- } |
+ if (!boundToUs) { |
+ return; |
+ } |
- mServiceConnectComplete = true; |
+ mServiceConnectComplete = true; |
- // Run the setup if the connection parameters have already been provided. If |
- // not, doConnectionSetupLocked() will be called from setupConnection(). |
- if (mConnectionParams != null) { |
- doConnectionSetupLocked(); |
- } |
- } finally { |
- TraceEvent.end( |
- "BaseChildProcessConnection.ChildServiceConnection.onServiceConnected"); |
+ // Run the setup if the connection parameters have already been provided. If |
+ // not, doConnectionSetupLocked() will be called from setupConnection(). |
+ if (mConnectionParams != null) { |
+ doConnectionSetupLocked(); |
} |
+ } finally { |
+ TraceEvent.end("BaseChildProcessConnection.ChildServiceConnection.onServiceConnected"); |
} |
} |
private void onServiceDisconnectedOnLauncherThread() { |
assert LauncherThread.runningOnLauncherThread(); |
- synchronized (mLock) { |
- // Ensure that the disconnection logic runs only once (instead of once per each |
- // ChildServiceConnection). |
- if (mServiceDisconnected) { |
- return; |
- } |
- mServiceDisconnected = true; |
- Log.w(TAG, "onServiceDisconnected (crash or killed by oom): pid=%d", mPid); |
- stop(); // We don't want to auto-restart on crash. Let the browser do that. |
- mDeathCallback.onChildProcessDied(BaseChildProcessConnection.this); |
- // If we have a pending connection callback, we need to communicate the failure to |
- // the caller. |
- if (mConnectionCallback != null) { |
- mConnectionCallback.onConnected(null); |
- } |
- mConnectionCallback = null; |
+ // Ensure that the disconnection logic runs only once (instead of once per each |
+ // ChildServiceConnection). |
+ if (mServiceDisconnected) { |
+ return; |
} |
+ mServiceDisconnected = true; |
+ Log.w(TAG, "onServiceDisconnected (crash or killed by oom): pid=%d", mPid); |
+ stop(); // We don't want to auto-restart on crash. Let the browser do that. |
+ mDeathCallback.onChildProcessDied(BaseChildProcessConnection.this); |
+ // If we have a pending connection callback, we need to communicate the failure to |
+ // the caller. |
+ if (mConnectionCallback != null) { |
+ mConnectionCallback.onConnected(null); |
+ } |
+ mConnectionCallback = null; |
} |
private void onSetupConnectionResult(int pid) { |
- synchronized (mLock) { |
- mPid = pid; |
- assert mPid != 0 : "Child service claims to be run by a process of pid=0."; |
+ mPid = pid; |
+ assert mPid != 0 : "Child service claims to be run by a process of pid=0."; |
- if (mConnectionCallback != null) { |
- mConnectionCallback.onConnected(this); |
- } |
- mConnectionCallback = null; |
+ if (mConnectionCallback != null) { |
+ mConnectionCallback.onConnected(this); |
} |
+ mConnectionCallback = null; |
} |
/** |
@@ -454,7 +433,6 @@ public abstract class BaseChildProcessConnection { |
* connection has been established (as signaled by onServiceConnected()). These two events can |
* happen in any order. Has to be called with mLock. |
*/ |
- @GuardedBy("mLock") |
private void doConnectionSetupLocked() { |
try { |
TraceEvent.begin("BaseChildProcessConnection.doConnectionSetupLocked"); |
@@ -498,10 +476,12 @@ public abstract class BaseChildProcessConnection { |
protected abstract void unbind(); |
protected ChildServiceConnection createServiceConnection(int bindFlags) { |
+ assert LauncherThread.runningOnLauncherThread(); |
return new ChildServiceConnectionImpl(bindFlags); |
} |
protected boolean shouldBindAsExportedService() { |
+ assert LauncherThread.runningOnLauncherThread(); |
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && getCreationParams() != null |
&& getCreationParams().getIsExternalService() |
&& isExportedService(isSandboxed(), getContext(), getServiceName()); |
@@ -529,15 +509,11 @@ public abstract class BaseChildProcessConnection { |
@VisibleForTesting |
public void crashServiceForTesting() throws RemoteException { |
- synchronized (mLock) { |
- mService.crashIntentionallyForTesting(); |
- } |
+ mService.crashIntentionallyForTesting(); |
} |
@VisibleForTesting |
- public boolean isConnected() { |
- synchronized (mLock) { |
- return mService != null; |
- } |
+ boolean isConnected() { |
+ return mService != null; |
} |
} |