Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package org.chromium.content.browser; | |
| 6 | |
| 7 import android.content.Context; | |
| 8 import android.os.Build; | |
| 9 import android.os.Bundle; | |
| 10 | |
| 11 import org.chromium.base.Log; | |
| 12 import org.chromium.base.VisibleForTesting; | |
| 13 import org.chromium.base.process_launcher.ChildProcessCreationParams; | |
| 14 | |
| 15 import javax.annotation.concurrent.GuardedBy; | |
| 16 | |
| 17 /** | |
| 18 * ManagedChildProcessConnection is a connection to a child service that can hol d several bindings | |
| 19 * to the service so it can be more or less agressively protected against OOM. | |
| 20 */ | |
| 21 public class ManagedChildProcessConnection extends BaseChildProcessConnection { | |
| 22 private static final String TAG = "ManChildProcessConn"; | |
| 23 | |
| 24 public static final Factory FACTORY = new BaseChildProcessConnection.Factory () { | |
| 25 @Override | |
| 26 public BaseChildProcessConnection create(Context context, int number, bo olean sandboxed, | |
| 27 DeathCallback deathCallback, String serviceClassName, | |
| 28 Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams) { | |
| 29 ManagedChildProcessConnection connection = | |
| 30 new ManagedChildProcessConnection(context, number, sandboxed , deathCallback, | |
| 31 serviceClassName, childProcessCommonParameters, crea tionParams); | |
| 32 connection.initBindings(); | |
| 33 return connection; | |
| 34 } | |
| 35 }; | |
| 36 | |
| 37 // Synchronization: While most internal flow occurs on the UI thread, the pu blic API | |
| 38 // (specifically start and stop) may be called from any thread, hence all en try point methods | |
| 39 // into the class are synchronized on the lock to protect access to these me mbers. | |
| 40 private final Object mBindingLock = new Object(); | |
| 41 | |
| 42 // Initial binding protects the newly spawned process from being killed befo re it is put to use, | |
| 43 // it is maintained between calls to start() and removeInitialBinding(). | |
| 44 @GuardedBy("mBindingLock") | |
| 45 private ChildServiceConnection mInitialBinding; | |
| 46 | |
| 47 // Strong binding will make the service priority equal to the priority of th e activity. We want | |
| 48 // the OS to be able to kill background renderers as it kills other backgrou nd apps, so strong | |
| 49 // bindings are maintained only for services that are active at the moment ( between | |
| 50 // addStrongBinding() and removeStrongBinding()). | |
| 51 @GuardedBy("mBindingLock") | |
| 52 private ChildServiceConnection mStrongBinding; | |
| 53 | |
| 54 // Low priority binding maintained in the entire lifetime of the connection, i.e. between calls | |
| 55 // to start() and stop(). | |
| 56 @GuardedBy("mBindingLock") | |
| 57 private ChildServiceConnection mWaivedBinding; | |
| 58 | |
| 59 // Incremented on addStrongBinding(), decremented on removeStrongBinding(). | |
| 60 @GuardedBy("mBindingLock") | |
| 61 private int mStrongBindingCount; | |
| 62 | |
| 63 // Moderate binding will make the service priority equal to the priority of a visible process | |
| 64 // while the app is in the foreground. It will stay bound only while the app is in the | |
| 65 // foreground to protect a background process from the system out-of-memory killer. | |
| 66 @GuardedBy("mBindingLock") | |
| 67 private ChildServiceConnection mModerateBinding; | |
| 68 | |
| 69 @GuardedBy("mBindingLock") | |
| 70 private boolean mWasOomProtectedOnUnbind; | |
| 71 | |
| 72 @VisibleForTesting | |
| 73 ManagedChildProcessConnection(Context context, int number, boolean sandboxed , | |
| 74 DeathCallback deathCallback, String serviceClassName, | |
| 75 Bundle childProcessCommonParameters, ChildProcessCreationParams crea tionParams) { | |
| 76 super(context, number, sandboxed, deathCallback, serviceClassName, | |
| 77 childProcessCommonParameters, creationParams); | |
| 78 } | |
| 79 | |
| 80 @VisibleForTesting | |
| 81 protected void initBindings() { | |
|
boliu
2017/04/20 22:33:34
again, nothing is overriding this? can just be par
Jay Civelli
2017/04/25 06:02:46
Oh right, we can do this now. (I used that origina
| |
| 82 int initialFlags = Context.BIND_AUTO_CREATE; | |
| 83 int extraBindFlags = 0; | |
| 84 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && getCreationParams( ) != null | |
|
boliu
2017/04/20 22:33:34
avoid duplicating this if condition, just expand i
Jay Civelli
2017/04/25 06:02:46
Done.
| |
| 85 && getCreationParams().getIsExternalService() | |
| 86 && isExportedService(isSandboxed(), getContext(), getServiceName ())) { | |
| 87 extraBindFlags = Context.BIND_EXTERNAL_SERVICE; | |
| 88 } | |
| 89 | |
| 90 synchronized (mBindingLock) { | |
| 91 mInitialBinding = createServiceConnection(initialFlags | extraBindFl ags); | |
| 92 mStrongBinding = createServiceConnection( | |
| 93 Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT | extraBin dFlags); | |
| 94 mWaivedBinding = createServiceConnection( | |
| 95 Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY | ext raBindFlags); | |
| 96 mModerateBinding = createServiceConnection(Context.BIND_AUTO_CREATE | extraBindFlags); | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 @Override | |
| 101 protected boolean bind() { | |
| 102 synchronized (mBindingLock) { | |
| 103 if (!mInitialBinding.bind()) { | |
| 104 return false; | |
| 105 } | |
| 106 mWaivedBinding.bind(); | |
| 107 } | |
| 108 return true; | |
| 109 } | |
| 110 | |
| 111 @Override | |
| 112 public void unbind() { | |
| 113 synchronized (mBindingLock) { | |
| 114 mWasOomProtectedOnUnbind = isCurrentlyOomProtected(); | |
| 115 mInitialBinding.unbind(); | |
| 116 mStrongBinding.unbind(); | |
| 117 mWaivedBinding.unbind(); | |
| 118 mModerateBinding.unbind(); | |
| 119 mStrongBindingCount = 0; | |
| 120 } | |
| 121 } | |
| 122 | |
| 123 public boolean isInitialBindingBound() { | |
| 124 synchronized (mBindingLock) { | |
| 125 return mInitialBinding.isBound(); | |
| 126 } | |
| 127 } | |
| 128 | |
| 129 public boolean isStrongBindingBound() { | |
| 130 synchronized (mBindingLock) { | |
| 131 return mStrongBinding.isBound(); | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 public void removeInitialBinding() { | |
| 136 synchronized (mBindingLock) { | |
| 137 mInitialBinding.unbind(); | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 public boolean isOomProtectedOrWasWhenDied() { | |
| 142 synchronized (mBindingLock) { | |
| 143 if (isConnected()) { | |
| 144 return isCurrentlyOomProtected(); | |
| 145 } | |
| 146 return mWasOomProtectedOnUnbind; | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 private boolean isCurrentlyOomProtected() { | |
| 151 synchronized (mBindingLock) { | |
| 152 return mInitialBinding.isBound() || mStrongBinding.isBound(); | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 public void dropOomBindings() { | |
| 157 synchronized (mBindingLock) { | |
| 158 mInitialBinding.unbind(); | |
| 159 | |
| 160 mStrongBindingCount = 0; | |
| 161 mStrongBinding.unbind(); | |
| 162 | |
| 163 mModerateBinding.unbind(); | |
| 164 } | |
| 165 } | |
| 166 | |
| 167 public void addStrongBinding() { | |
| 168 synchronized (mBindingLock) { | |
| 169 if (!isConnected()) { | |
| 170 Log.w(TAG, "The connection is not bound for %d", getPid()); | |
| 171 return; | |
| 172 } | |
| 173 if (mStrongBindingCount == 0) { | |
| 174 mStrongBinding.bind(); | |
| 175 } | |
| 176 mStrongBindingCount++; | |
| 177 } | |
| 178 } | |
| 179 | |
| 180 public void removeStrongBinding() { | |
| 181 synchronized (mBindingLock) { | |
| 182 if (!isConnected()) { | |
| 183 Log.w(TAG, "The connection is not bound for %d", getPid()); | |
| 184 return; | |
| 185 } | |
| 186 assert mStrongBindingCount > 0; | |
| 187 mStrongBindingCount--; | |
| 188 if (mStrongBindingCount == 0) { | |
| 189 mStrongBinding.unbind(); | |
| 190 } | |
| 191 } | |
| 192 } | |
| 193 | |
| 194 public boolean isModerateBindingBound() { | |
| 195 synchronized (mBindingLock) { | |
| 196 return mModerateBinding.isBound(); | |
| 197 } | |
| 198 } | |
| 199 | |
| 200 public void addModerateBinding() { | |
| 201 synchronized (mBindingLock) { | |
| 202 if (!isConnected()) { | |
| 203 Log.w(TAG, "The connection is not bound for %d", getPid()); | |
| 204 return; | |
| 205 } | |
| 206 mModerateBinding.bind(); | |
| 207 } | |
| 208 } | |
| 209 | |
| 210 public void removeModerateBinding() { | |
| 211 synchronized (mBindingLock) { | |
| 212 if (!isConnected()) { | |
| 213 Log.w(TAG, "The connection is not bound for %d", getPid()); | |
| 214 return; | |
| 215 } | |
| 216 mModerateBinding.unbind(); | |
| 217 } | |
| 218 } | |
| 219 } | |
| OLD | NEW |