Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1420)

Unified Diff: content/public/android/java/src/org/chromium/content/browser/ManagedChildProcessConnection.java

Issue 2828793002: Refactoring ChildProcessConnection. (Closed)
Patch Set: More test fixing. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/public/android/java/src/org/chromium/content/browser/ManagedChildProcessConnection.java
diff --git a/content/public/android/java/src/org/chromium/content/browser/ManagedChildProcessConnection.java b/content/public/android/java/src/org/chromium/content/browser/ManagedChildProcessConnection.java
new file mode 100644
index 0000000000000000000000000000000000000000..99f41223869821f5ca8c04537e8084c2ec9336f6
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/browser/ManagedChildProcessConnection.java
@@ -0,0 +1,225 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.browser;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import org.chromium.base.Log;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.base.process_launcher.ChildProcessCreationParams;
+
+import javax.annotation.concurrent.GuardedBy;
+
+/**
+ * ManagedChildProcessConnection is a connection to a child service that can hold several bindings
+ * to the service so it can be more or less agressively protected against OOM.
+ */
+public class ManagedChildProcessConnection extends BaseChildProcessConnection {
+ private static final String TAG = "ManChildProcessConn";
+
+ public static final Factory FACTORY = new BaseChildProcessConnection.Factory() {
+ @Override
+ public BaseChildProcessConnection create(Context context, int number, boolean sandboxed,
+ DeathCallback deathCallback, String serviceClassName,
+ Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams) {
+ return new ManagedChildProcessConnection(context, number, sandboxed, deathCallback,
+ serviceClassName, childProcessCommonParameters, creationParams);
+ }
+ };
+
+ // 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.
+ private final Object mBindingLock = new Object();
+
+ // Initial binding protects the newly spawned process from being killed before it is put to use,
+ // it is maintained between calls to start() and removeInitialBinding().
+ @GuardedBy("mBindingLock")
+ private final ChildServiceConnection mInitialBinding;
+
+ // Strong binding will make the service priority equal to the priority of the activity. We want
+ // the OS to be able to kill background renderers as it kills other background apps, so strong
+ // bindings are maintained only for services that are active at the moment (between
+ // addStrongBinding() and removeStrongBinding()).
+ @GuardedBy("mBindingLock")
+ private final ChildServiceConnection mStrongBinding;
+
+ // Low priority binding maintained in the entire lifetime of the connection, i.e. between calls
+ // to start() and stop().
+ @GuardedBy("mBindingLock")
+ private final ChildServiceConnection mWaivedBinding;
+
+ // Incremented on addStrongBinding(), decremented on removeStrongBinding().
+ @GuardedBy("mBindingLock")
+ private int mStrongBindingCount;
+
+ // Moderate binding will make the service priority equal to the priority of a visible process
+ // while the app is in the foreground. It will stay bound only while the app is in the
+ // foreground to protect a background process from the system out-of-memory killer.
+ @GuardedBy("mBindingLock")
+ private final ChildServiceConnection mModerateBinding;
+
+ @GuardedBy("mBindingLock")
+ private boolean mWasOomProtectedOnUnbind;
+
+ @VisibleForTesting
+ ManagedChildProcessConnection(Context context, int number, boolean sandboxed,
+ DeathCallback deathCallback, String serviceClassName,
+ Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams) {
+ super(context, number, sandboxed, deathCallback, serviceClassName,
+ childProcessCommonParameters, creationParams);
+
+ int initialFlags = Context.BIND_AUTO_CREATE;
+ int extraBindFlags = shouldBindAsExportedService() ? Context.BIND_EXTERNAL_SERVICE : 0;
+
+ synchronized (mBindingLock) {
+ mInitialBinding = createServiceConnection(initialFlags | extraBindFlags);
+ mStrongBinding = createServiceConnection(
+ Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT | extraBindFlags);
+ mWaivedBinding = createServiceConnection(
+ Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY | extraBindFlags);
+ mModerateBinding = createServiceConnection(Context.BIND_AUTO_CREATE | extraBindFlags);
+ }
+ }
+
+ @Override
+ protected boolean bind() {
+ synchronized (mBindingLock) {
+ if (!mInitialBinding.bind()) {
+ return false;
+ }
+ mWaivedBinding.bind();
+ }
+ return true;
+ }
+
+ @Override
+ public void unbind() {
+ synchronized (mBindingLock) {
+ if (!isBound()) {
+ return;
+ }
+ mWasOomProtectedOnUnbind = isCurrentlyOomProtected();
+ mInitialBinding.unbind();
+ mStrongBinding.unbind();
+ mWaivedBinding.unbind();
+ mModerateBinding.unbind();
+ mStrongBindingCount = 0;
+ }
+ }
+
+ @GuardedBy("mBindingLock")
+ private boolean isBound() {
+ return mInitialBinding.isBound() || mStrongBinding.isBound() || mWaivedBinding.isBound()
+ || mModerateBinding.isBound();
+ }
+
+ public boolean isInitialBindingBound() {
+ synchronized (mBindingLock) {
+ return mInitialBinding.isBound();
+ }
+ }
+
+ public boolean isStrongBindingBound() {
+ synchronized (mBindingLock) {
+ return mStrongBinding.isBound();
+ }
+ }
+
+ public void removeInitialBinding() {
+ synchronized (mBindingLock) {
+ mInitialBinding.unbind();
+ }
+ }
+
+ public boolean isOomProtectedOrWasWhenDied() {
+ // Call isConnected() outside of the synchronized block or we could deadlock.
+ final boolean isConnected = isConnected();
+ synchronized (mBindingLock) {
+ if (isConnected) {
+ return isCurrentlyOomProtected();
+ }
+ return mWasOomProtectedOnUnbind;
+ }
+ }
+
+ @GuardedBy("mBindingLock")
+ private boolean isCurrentlyOomProtected() {
+ return mInitialBinding.isBound() || mStrongBinding.isBound();
+ }
+
+ public void dropOomBindings() {
+ synchronized (mBindingLock) {
+ mInitialBinding.unbind();
+
+ mStrongBindingCount = 0;
+ mStrongBinding.unbind();
+
+ mModerateBinding.unbind();
+ }
+ }
+
+ public void addStrongBinding() {
+ // Call isConnected() outside of the synchronized block or we could deadlock.
+ final boolean isConnected = isConnected();
+ synchronized (mBindingLock) {
+ if (!isConnected) {
+ Log.w(TAG, "The connection is not bound for %d", getPid());
+ return;
+ }
+ if (mStrongBindingCount == 0) {
+ mStrongBinding.bind();
+ }
+ mStrongBindingCount++;
+ }
+ }
+
+ public void removeStrongBinding() {
+ // Call isConnected() outside of the synchronized block or we could deadlock.
+ final boolean isConnected = isConnected();
+ synchronized (mBindingLock) {
+ if (!isConnected) {
+ Log.w(TAG, "The connection is not bound for %d", getPid());
+ return;
+ }
+ assert mStrongBindingCount > 0;
+ mStrongBindingCount--;
+ if (mStrongBindingCount == 0) {
+ mStrongBinding.unbind();
+ }
+ }
+ }
+
+ public boolean isModerateBindingBound() {
+ synchronized (mBindingLock) {
+ return mModerateBinding.isBound();
+ }
+ }
+
+ public void addModerateBinding() {
+ // Call isConnected() outside of the synchronized block or we could deadlock.
+ final boolean isConnected = isConnected();
+ synchronized (mBindingLock) {
+ if (!isConnected) {
+ Log.w(TAG, "The connection is not bound for %d", getPid());
+ return;
+ }
+ mModerateBinding.bind();
+ }
+ }
+
+ public void removeModerateBinding() {
+ // Call isConnected() outside of the synchronized block or we could deadlock.
+ final boolean isConnected = isConnected();
+ synchronized (mBindingLock) {
+ if (!isConnected) {
+ Log.w(TAG, "The connection is not bound for %d", getPid());
+ return;
+ }
+ mModerateBinding.unbind();
+ }
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698