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 |