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

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/BaseChildProcessConnection.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 unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 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.Intent; 9 import android.content.Intent;
10 import android.content.ServiceConnection; 10 import android.content.ServiceConnection;
11 import android.content.pm.PackageManager; 11 import android.content.pm.PackageManager;
12 import android.content.pm.ServiceInfo; 12 import android.content.pm.ServiceInfo;
13 import android.os.Build; 13 import android.os.Build;
14 import android.os.Bundle; 14 import android.os.Bundle;
15 import android.os.IBinder; 15 import android.os.IBinder;
16 import android.os.RemoteException; 16 import android.os.RemoteException;
17 17
18 import org.chromium.base.Log; 18 import org.chromium.base.Log;
19 import org.chromium.base.TraceEvent; 19 import org.chromium.base.TraceEvent;
20 import org.chromium.base.VisibleForTesting; 20 import org.chromium.base.VisibleForTesting;
21 import org.chromium.base.process_launcher.ChildProcessCreationParams; 21 import org.chromium.base.process_launcher.ChildProcessCreationParams;
22 import org.chromium.base.process_launcher.FileDescriptorInfo; 22 import org.chromium.base.process_launcher.FileDescriptorInfo;
23 import org.chromium.base.process_launcher.ICallbackInt; 23 import org.chromium.base.process_launcher.ICallbackInt;
24 import org.chromium.base.process_launcher.IChildProcessService; 24 import org.chromium.base.process_launcher.IChildProcessService;
25 25
26 import java.io.IOException; 26 import java.io.IOException;
27 27
28 import javax.annotation.Nullable; 28 import javax.annotation.Nullable;
29 import javax.annotation.concurrent.GuardedBy;
29 30
30 /** 31 /**
31 * Manages a connection between the browser activity and a child service. 32 * Manages a connection between the browser activity and a child service.
32 */ 33 */
33 public class ChildProcessConnectionImpl implements ChildProcessConnection { 34 public abstract class BaseChildProcessConnection {
34 private final Context mContext; 35 private static final String TAG = "BaseChildProcessConn";
35 private final int mServiceNumber;
36 private final boolean mInSandbox;
37 private final ChildProcessConnection.DeathCallback mDeathCallback;
38 private final ComponentName mServiceName;
39 36
40 // Synchronization: While most internal flow occurs on the UI thread, the pu blic API 37 /**
41 // (specifically start and stop) may be called from any thread, hence all en try point methods 38 * Used to notify the consumer about disconnection of the service. This call back is provided
42 // into the class are synchronized on the lock to protect access to these me mbers. 39 * earlier than ConnectionCallbacks below, as a child process might die befo re the connection is
43 private final Object mLock = new Object(); 40 * fully set up.
44 private IChildProcessService mService; 41 */
45 // Set to true when the service connection callback runs. This differs from 42 interface DeathCallback {
46 // mServiceConnectComplete, which tracks that the connection completed succe ssfully. 43 // Called on Launcher thread.
47 private boolean mDidOnServiceConnected; 44 void onChildProcessDied(BaseChildProcessConnection connection);
48 // Set to true when the service connected successfully.
49 private boolean mServiceConnectComplete;
50 // Set to true when the service disconnects, as opposed to being properly cl osed. This happens
51 // when the process crashes or gets killed by the system out-of-memory kille r.
52 private boolean mServiceDisconnected;
53 // When the service disconnects (i.e. mServiceDisconnected is set to true), the status of the
54 // oom bindings is stashed here for future inspection.
55 private boolean mWasOomProtected;
56 private int mPid; // Process ID of the corresponding child process.
57 // Initial binding protects the newly spawned process from being killed befo re it is put to use,
58 // it is maintained between calls to start() and removeInitialBinding().
59 private ChildServiceConnection mInitialBinding;
60 // Strong binding will make the service priority equal to the priority of th e activity. We want
61 // the OS to be able to kill background renderers as it kills other backgrou nd apps, so strong
62 // bindings are maintained only for services that are active at the moment ( between
63 // addStrongBinding() and removeStrongBinding()).
64 private ChildServiceConnection mStrongBinding;
65 // Low priority binding maintained in the entire lifetime of the connection, i.e. between calls
66 // to start() and stop().
67 private ChildServiceConnection mWaivedBinding;
68 // Incremented on addStrongBinding(), decremented on removeStrongBinding().
69 private int mStrongBindingCount;
70 // Moderate binding will make the service priority equal to the priority of a visible process
71 // while the app is in the foreground. It will stay bound only while the app is in the
72 // foreground to protect a background process from the system out-of-memory killer.
73 private ChildServiceConnection mModerateBinding;
74
75 // Parameters passed to the child process through the service binding intent .
76 // If the service gets recreated by the framework the intent will be reused, so these parameters
77 // should be common to all processes of that type.
78 private final Bundle mChildProcessCommonParameters;
79
80 private final boolean mAlwaysInForeground;
81 private final ChildProcessCreationParams mCreationParams;
82
83 // Caches whether non-sandboxed and sandboxed services require an extra
84 // binding flag provided via ChildProcessCreationParams.
85 // TODO(mnaganov): Get rid of it after the release of the next Android SDK.
86 private static Boolean sNeedsExtrabindFlags[] = new Boolean[2];
87
88 private static final String TAG = "ChildProcessConnect";
89
90 private static class ConnectionParams {
91 final String[] mCommandLine;
92 final FileDescriptorInfo[] mFilesToBeMapped;
93 final IBinder mCallback;
94
95 ConnectionParams(
96 String[] commandLine, FileDescriptorInfo[] filesToBeMapped, IBin der callback) {
97 mCommandLine = commandLine;
98 mFilesToBeMapped = filesToBeMapped;
99 mCallback = callback;
100 }
101 } 45 }
102 46
103 // This is set in start() and is used in onServiceConnected(). 47 /**
104 private ChildProcessConnection.StartCallback mStartCallback; 48 * Used to notify the consumer about the process start. These callbacks will be invoked before
49 * the ConnectionCallbacks.
50 */
51 interface StartCallback {
52 /**
53 * Called when the child process has successfully started and is ready f or connection
54 * setup.
55 */
56 void onChildStarted();
105 57
106 // This is set in setupConnection() and is later used in doConnectionSetupLo cked(), after which 58 /**
107 // the variable is cleared. Therefore this is only valid while the connectio n is being set up. 59 * Called when the child process failed to start. This can happen if the process is already
108 private ConnectionParams mConnectionParams; 60 * in use by another client.
61 */
62 void onChildStartFailed();
63 }
109 64
110 // Callback provided in setupConnection() that will communicate the result t o the caller. This 65 /**
111 // has to be called exactly once after setupConnection(), even if setup fail s, so that the 66 * Used to notify the consumer about the connection being established.
112 // caller can free up resources associated with the setup attempt. This is s et to null after the 67 */
113 // call. 68 interface ConnectionCallback {
114 private ChildProcessConnection.ConnectionCallback mConnectionCallback; 69 /**
70 * Called when the connection to the service is established.
71 * @param connecion the connection object to the child process
72 */
73 void onConnected(BaseChildProcessConnection connection);
74 }
115 75
116 private class ChildServiceConnection implements ServiceConnection { 76 /** Used to create specialization connection instances. */
77 interface Factory {
78 BaseChildProcessConnection create(Context context, int number, boolean s andboxed,
79 DeathCallback deathCallback, String serviceClassName,
80 Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams);
81 }
82
83 /** Interface representing a connection to the Android service. Can be mocke d in unit-tests. */
84 protected interface ChildServiceConnection {
85 boolean bind();
86 void unbind();
87 boolean isBound();
88 }
89
90 /** Implementation of ChildServiceConnection that does connect to a service. */
91 protected class ChildServiceConnectionImpl
92 implements ChildServiceConnection, ServiceConnection {
93 private final int mBindFlags;
117 private boolean mBound; 94 private boolean mBound;
118 95
119 private final int mBindFlags;
120
121 private Intent createServiceBindIntent() { 96 private Intent createServiceBindIntent() {
122 Intent intent = new Intent(); 97 Intent intent = new Intent();
123 if (mCreationParams != null) { 98 if (mCreationParams != null) {
124 mCreationParams.addIntentExtras(intent); 99 mCreationParams.addIntentExtras(intent);
125 } 100 }
126 intent.setComponent(mServiceName); 101 intent.setComponent(mServiceName);
127 return intent; 102 return intent;
128 } 103 }
129 104
130 public ChildServiceConnection(int bindFlags) { 105 private ChildServiceConnectionImpl(int bindFlags) {
131 mBindFlags = bindFlags; 106 mBindFlags = bindFlags;
132 } 107 }
133 108
134 boolean bind() { 109 @Override
110 public boolean bind() {
135 if (!mBound) { 111 if (!mBound) {
136 try { 112 try {
137 TraceEvent.begin("ChildProcessConnectionImpl.ChildServiceCon nection.bind"); 113 TraceEvent.begin("BaseChildProcessConnection.ChildServiceCon nection.bind");
138 Intent intent = createServiceBindIntent(); 114 Intent intent = createServiceBindIntent();
139 if (mChildProcessCommonParameters != null) { 115 if (mChildProcessCommonParameters != null) {
140 intent.putExtras(mChildProcessCommonParameters); 116 intent.putExtras(mChildProcessCommonParameters);
141 } 117 }
142 mBound = mContext.bindService(intent, this, mBindFlags); 118 mBound = mContext.bindService(intent, this, mBindFlags);
143 } finally { 119 } finally {
144 TraceEvent.end("ChildProcessConnectionImpl.ChildServiceConne ction.bind"); 120 TraceEvent.end("BaseChildProcessConnection.ChildServiceConne ction.bind");
145 } 121 }
146 } 122 }
147 return mBound; 123 return mBound;
148 } 124 }
149 125
150 void unbind() { 126 @Override
127 public void unbind() {
151 if (mBound) { 128 if (mBound) {
152 mContext.unbindService(this); 129 mContext.unbindService(this);
153 mBound = false; 130 mBound = false;
154 } 131 }
155 } 132 }
156 133
157 boolean isBound() { 134 @Override
135 public boolean isBound() {
158 return mBound; 136 return mBound;
159 } 137 }
160 138
161 @Override 139 @Override
162 public void onServiceConnected(ComponentName className, final IBinder se rvice) { 140 public void onServiceConnected(ComponentName className, final IBinder se rvice) {
163 LauncherThread.post(new Runnable() { 141 LauncherThread.post(new Runnable() {
164 @Override 142 @Override
165 public void run() { 143 public void run() {
166 ChildProcessConnectionImpl.this.onServiceConnectedOnLauncher Thread(service); 144 BaseChildProcessConnection.this.onServiceConnectedOnLauncher Thread(service);
167 } 145 }
168 }); 146 });
169 } 147 }
170 148
171 // Called on the main thread to notify that the child service did not di sconnect gracefully. 149 // Called on the main thread to notify that the child service did not di sconnect gracefully.
172 @Override 150 @Override
173 public void onServiceDisconnected(ComponentName className) { 151 public void onServiceDisconnected(ComponentName className) {
174 LauncherThread.post(new Runnable() { 152 LauncherThread.post(new Runnable() {
175 @Override 153 @Override
176 public void run() { 154 public void run() {
177 ChildProcessConnectionImpl.this.onServiceDisconnectedOnLaunc herThread(); 155 BaseChildProcessConnection.this.onServiceDisconnectedOnLaunc herThread();
178 } 156 }
179 }); 157 });
180 } 158 }
181 } 159 }
182 160
183 ChildProcessConnectionImpl(Context context, int number, boolean inSandbox, 161 // Caches whether non-sandboxed and sandboxed services require an extra
184 ChildProcessConnection.DeathCallback deathCallback, String serviceCl assName, 162 // binding flag provided via ChildProcessCreationParams.
185 Bundle childProcessCommonParameters, boolean alwaysInForeground, 163 // TODO(mnaganov): Get rid of it after the release of the next Android SDK.
186 ChildProcessCreationParams creationParams) { 164 private static Boolean sNeedsExtrabindFlags[] = new Boolean[2];
165 private final Context mContext;
166 private final int mServiceNumber;
167 private final boolean mSandboxed;
168 private final BaseChildProcessConnection.DeathCallback mDeathCallback;
169 private final ComponentName mServiceName;
170
171 // Parameters passed to the child process through the service binding intent .
172 // If the service gets recreated by the framework the intent will be reused, so these parameters
173 // should be common to all processes of that type.
174 private final Bundle mChildProcessCommonParameters;
175
176 private final ChildProcessCreationParams mCreationParams;
177
178 private static class ConnectionParams {
179 final String[] mCommandLine;
180 final FileDescriptorInfo[] mFilesToBeMapped;
181 final IBinder mCallback;
182
183 ConnectionParams(
184 String[] commandLine, FileDescriptorInfo[] filesToBeMapped, IBin der callback) {
185 mCommandLine = commandLine;
186 mFilesToBeMapped = filesToBeMapped;
187 mCallback = callback;
188 }
189 }
190
191 // Synchronization: While most internal flow occurs on the UI thread, the pu blic API
192 // (specifically start and stop) may be called from any thread, hence all en try point methods
193 // into the class are synchronized on the lock to protect access to these me mbers.
194 // TODO(jcivelli): crbug.com/714657 remove this lock.
195 private final Object mLock = new Object();
196
197 // This is set in start() and is used in onServiceConnected().
198 @GuardedBy("mLock")
199 private StartCallback mStartCallback;
200
201 // This is set in setupConnection() and is later used in doConnectionSetupLo cked(), after which
202 // the variable is cleared. Therefore this is only valid while the connectio n is being set up.
203 @GuardedBy("mLock")
204 private ConnectionParams mConnectionParams;
205
206 // Callback provided in setupConnection() that will communicate the result t o the caller. This
207 // has to be called exactly once after setupConnection(), even if setup fail s, so that the
208 // caller can free up resources associated with the setup attempt. This is s et to null after the
209 // call.
210 @GuardedBy("mLock")
211 private ConnectionCallback mConnectionCallback;
212
213 @GuardedBy("mLock")
214 private IChildProcessService mService;
215
216 // Set to true when the service connection callback runs. This differs from
217 // mServiceConnectComplete, which tracks that the connection completed succe ssfully.
218 @GuardedBy("mLock")
219 private boolean mDidOnServiceConnected;
220
221 // Set to true when the service connected successfully.
222 @GuardedBy("mLock")
223 private boolean mServiceConnectComplete;
224
225 // Set to true when the service disconnects, as opposed to being properly cl osed. This happens
226 // when the process crashes or gets killed by the system out-of-memory kille r.
227 @GuardedBy("mLock")
228 private boolean mServiceDisconnected;
229
230 // Process ID of the corresponding child process.
231 @GuardedBy("mLock")
232 private int mPid;
233
234 protected BaseChildProcessConnection(Context context, int number, boolean sa ndboxed,
235 DeathCallback deathCallback, String serviceClassName,
236 Bundle childProcessCommonParameters, ChildProcessCreationParams crea tionParams) {
187 mContext = context; 237 mContext = context;
188 mServiceNumber = number; 238 mServiceNumber = number;
189 mInSandbox = inSandbox; 239 mSandboxed = sandboxed;
190 mDeathCallback = deathCallback; 240 mDeathCallback = deathCallback;
191 String packageName = 241 String packageName =
192 creationParams != null ? creationParams.getPackageName() : conte xt.getPackageName(); 242 creationParams != null ? creationParams.getPackageName() : conte xt.getPackageName();
193 mServiceName = new ComponentName(packageName, serviceClassName + mServic eNumber); 243 mServiceName = new ComponentName(packageName, serviceClassName + mServic eNumber);
194 mChildProcessCommonParameters = childProcessCommonParameters; 244 mChildProcessCommonParameters = childProcessCommonParameters;
195 mAlwaysInForeground = alwaysInForeground;
196 mCreationParams = creationParams; 245 mCreationParams = creationParams;
197 int initialFlags = Context.BIND_AUTO_CREATE;
198 if (mAlwaysInForeground) initialFlags |= Context.BIND_IMPORTANT;
199 int extraBindFlags = 0;
200 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && mCreationParams != null
201 && mCreationParams.getIsExternalService()
202 && isExportedService(inSandbox, mContext, mServiceName)) {
203 extraBindFlags = Context.BIND_EXTERNAL_SERVICE;
204 }
205 mInitialBinding = new ChildServiceConnection(initialFlags | extraBindFla gs);
206 mStrongBinding = new ChildServiceConnection(
207 Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT | extraBindFla gs);
208 mWaivedBinding = new ChildServiceConnection(
209 Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY | extraBi ndFlags);
210 mModerateBinding = new ChildServiceConnection(Context.BIND_AUTO_CREATE | extraBindFlags);
211 } 246 }
212 247
213 private static boolean isExportedService(boolean inSandbox, Context context, 248 public final Context getContext() {
214 ComponentName serviceName) { 249 return mContext;
215 // Check for the cached value first. It is assumed that all pooled child services
216 // have identical attributes in the manifest.
217 final int arrayIndex = inSandbox ? 1 : 0;
218 if (sNeedsExtrabindFlags[arrayIndex] != null) {
219 return sNeedsExtrabindFlags[arrayIndex].booleanValue();
220 }
221 boolean result = false;
222 try {
223 PackageManager packageManager = context.getPackageManager();
224 ServiceInfo serviceInfo = packageManager.getServiceInfo(serviceName, 0);
225 result = serviceInfo.exported;
226 } catch (PackageManager.NameNotFoundException e) {
227 Log.e(TAG, "Could not retrieve info about service %s", serviceName, e);
228 }
229 sNeedsExtrabindFlags[arrayIndex] = Boolean.valueOf(result);
230 return result;
231 } 250 }
232 251
233 @Override 252 public final int getServiceNumber() {
234 public int getServiceNumber() {
235 return mServiceNumber; 253 return mServiceNumber;
236 } 254 }
237 255
238 @Override 256 public final boolean isSandboxed() {
239 public boolean isInSandbox() { 257 return mSandboxed;
240 return mInSandbox;
241 } 258 }
242 259
243 @Override 260 public final String getPackageName() {
244 public String getPackageName() {
245 return mCreationParams != null ? mCreationParams.getPackageName() 261 return mCreationParams != null ? mCreationParams.getPackageName()
246 : mContext.getPackageName(); 262 : mContext.getPackageName();
247 } 263 }
248 264
249 @Override 265 public final ChildProcessCreationParams getCreationParams() {
250 public ChildProcessCreationParams getCreationParams() {
251 return mCreationParams; 266 return mCreationParams;
252 } 267 }
253 268
254 @Override 269 public final IChildProcessService getService() {
255 public IChildProcessService getService() {
256 synchronized (mLock) { 270 synchronized (mLock) {
257 return mService; 271 return mService;
258 } 272 }
259 } 273 }
260 274
261 @Override 275 public final ComponentName getServiceName() {
276 return mServiceName;
277 }
278
279 /**
280 * @return the connection pid, or 0 if not yet connected
281 */
262 public int getPid() { 282 public int getPid() {
263 synchronized (mLock) { 283 synchronized (mLock) {
264 return mPid; 284 return mPid;
265 } 285 }
266 } 286 }
267 287
268 @Override 288 /**
269 public void start(ChildProcessConnection.StartCallback startCallback) { 289 * Starts a connection to an IChildProcessService. This must be followed by a call to
290 * setupConnection() to setup the connection parameters. start() and setupCo nnection() are
291 * separate to allow to pass whatever parameters are available in start(), a nd complete the
292 * remainder later while reducing the connection setup latency.
293 * @param startCallback (optional) callback when the child process starts or fails to start.
294 */
295 public void start(StartCallback startCallback) {
270 try { 296 try {
271 TraceEvent.begin("ChildProcessConnectionImpl.start"); 297 TraceEvent.begin("BaseChildProcessConnection.start");
272 assert LauncherThread.runningOnLauncherThread(); 298 assert LauncherThread.runningOnLauncherThread();
273 synchronized (mLock) { 299 synchronized (mLock) {
274 assert mConnectionParams == null : 300 assert mConnectionParams
275 "setupConnection() called before start() in ChildProcess ConnectionImpl."; 301 == null
302 : "setupConnection() called before start() in BaseChildP rocessConnection.";
276 303
277 mStartCallback = startCallback; 304 mStartCallback = startCallback;
278 305
279 if (!mInitialBinding.bind()) { 306 if (!bind()) {
280 Log.e(TAG, "Failed to establish the service connection."); 307 Log.e(TAG, "Failed to establish the service connection.");
281 // We have to notify the caller so that they can free-up ass ociated resources. 308 // We have to notify the caller so that they can free-up ass ociated resources.
282 // TODO(ppi): Can we hard-fail here? 309 // TODO(ppi): Can we hard-fail here?
283 mDeathCallback.onChildProcessDied(ChildProcessConnectionImpl .this); 310 mDeathCallback.onChildProcessDied(BaseChildProcessConnection .this);
284 } else {
285 mWaivedBinding.bind();
286 } 311 }
287 } 312 }
288 } finally { 313 } finally {
289 TraceEvent.end("ChildProcessConnectionImpl.start"); 314 TraceEvent.end("BaseChildProcessConnection.start");
290 } 315 }
291 } 316 }
292 317
293 @Override 318 /**
319 * Setups the connection after it was started with start().
320 * @param commandLine (optional) will be ignored if the command line was alr eady sent in start()
321 * @param filesToBeMapped a list of file descriptors that should be register ed
322 * @param callback optional client specified callbacks that the child can us e to communicate
323 * with the parent process
324 * @param connectionCallback will be called exactly once after the connectio n is set up or the
325 * setup fails
326 */
294 public void setupConnection(String[] commandLine, FileDescriptorInfo[] files ToBeMapped, 327 public void setupConnection(String[] commandLine, FileDescriptorInfo[] files ToBeMapped,
295 @Nullable IBinder callback, ConnectionCallback connectionCallback) { 328 @Nullable IBinder callback, ConnectionCallback connectionCallback) {
296 assert LauncherThread.runningOnLauncherThread(); 329 assert LauncherThread.runningOnLauncherThread();
297 synchronized (mLock) { 330 synchronized (mLock) {
298 assert mConnectionParams == null; 331 assert mConnectionParams == null;
299 if (mServiceDisconnected) { 332 if (mServiceDisconnected) {
300 Log.w(TAG, "Tried to setup a connection that already disconnecte d."); 333 Log.w(TAG, "Tried to setup a connection that already disconnecte d.");
301 connectionCallback.onConnected(0); 334 connectionCallback.onConnected(null);
302 return; 335 return;
303 } 336 }
304 try { 337 try {
305 TraceEvent.begin("ChildProcessConnectionImpl.setupConnection"); 338 TraceEvent.begin("BaseChildProcessConnection.setupConnection");
306 mConnectionCallback = connectionCallback; 339 mConnectionCallback = connectionCallback;
307 mConnectionParams = new ConnectionParams(commandLine, filesToBeM apped, callback); 340 mConnectionParams = new ConnectionParams(commandLine, filesToBeM apped, callback);
308 // Run the setup if the service is already connected. If not, 341 // Run the setup if the service is already connected. If not,
309 // doConnectionSetupLocked() will be called from onServiceConnec ted(). 342 // doConnectionSetupLocked() will be called from onServiceConnec ted().
310 if (mServiceConnectComplete) { 343 if (mServiceConnectComplete) {
311 doConnectionSetupLocked(); 344 doConnectionSetupLocked();
312 } 345 }
313 } finally { 346 } finally {
314 TraceEvent.end("ChildProcessConnectionImpl.setupConnection"); 347 TraceEvent.end("BaseChildProcessConnection.setupConnection");
315 } 348 }
316 } 349 }
317 } 350 }
318 351
319 @Override 352 /**
353 * Terminates the connection to IChildProcessService, closing all bindings. It is safe to call
354 * this multiple times.
355 */
320 public void stop() { 356 public void stop() {
321 synchronized (mLock) { 357 synchronized (mLock) {
322 mInitialBinding.unbind(); 358 unbind();
323 mStrongBinding.unbind(); 359 mService = null;
324 mWaivedBinding.unbind();
325 mModerateBinding.unbind();
326 mStrongBindingCount = 0;
327 if (mService != null) {
328 mService = null;
329 }
330 mConnectionParams = null; 360 mConnectionParams = null;
331 } 361 }
332 } 362 }
333 363
334 private void onServiceConnectedOnLauncherThread(IBinder service) { 364 private void onServiceConnectedOnLauncherThread(IBinder service) {
335 assert LauncherThread.runningOnLauncherThread(); 365 assert LauncherThread.runningOnLauncherThread();
336 synchronized (mLock) { 366 synchronized (mLock) {
337 // A flag from the parent class ensures we run the post-connection l ogic only once 367 // A flag from the parent class ensures we run the post-connection l ogic only once
338 // (instead of once per each ChildServiceConnection). 368 // (instead of once per each ChildServiceConnection).
339 if (mDidOnServiceConnected) { 369 if (mDidOnServiceConnected) {
340 return; 370 return;
341 } 371 }
342 try { 372 try {
343 TraceEvent.begin( 373 TraceEvent.begin(
344 "ChildProcessConnectionImpl.ChildServiceConnection.onSer viceConnected"); 374 "BaseChildProcessConnection.ChildServiceConnection.onSer viceConnected");
345 mDidOnServiceConnected = true; 375 mDidOnServiceConnected = true;
346 mService = IChildProcessService.Stub.asInterface(service); 376 mService = IChildProcessService.Stub.asInterface(service);
347 377
348 StartCallback startCallback = mStartCallback; 378 StartCallback startCallback = mStartCallback;
349 mStartCallback = null; 379 mStartCallback = null;
350 380
351 final boolean bindCheck = 381 final boolean bindCheck =
352 mCreationParams != null && mCreationParams.getBindToCall erCheck(); 382 mCreationParams != null && mCreationParams.getBindToCall erCheck();
353 boolean boundToUs = false; 383 boolean boundToUs = false;
354 try { 384 try {
(...skipping 19 matching lines...) Expand all
374 404
375 mServiceConnectComplete = true; 405 mServiceConnectComplete = true;
376 406
377 // Run the setup if the connection parameters have already been provided. If 407 // Run the setup if the connection parameters have already been provided. If
378 // not, doConnectionSetupLocked() will be called from setupConne ction(). 408 // not, doConnectionSetupLocked() will be called from setupConne ction().
379 if (mConnectionParams != null) { 409 if (mConnectionParams != null) {
380 doConnectionSetupLocked(); 410 doConnectionSetupLocked();
381 } 411 }
382 } finally { 412 } finally {
383 TraceEvent.end( 413 TraceEvent.end(
384 "ChildProcessConnectionImpl.ChildServiceConnection.onSer viceConnected"); 414 "BaseChildProcessConnection.ChildServiceConnection.onSer viceConnected");
385 } 415 }
386 } 416 }
387 } 417 }
388 418
389 private void onServiceDisconnectedOnLauncherThread() { 419 private void onServiceDisconnectedOnLauncherThread() {
390 assert LauncherThread.runningOnLauncherThread(); 420 assert LauncherThread.runningOnLauncherThread();
391 synchronized (mLock) { 421 synchronized (mLock) {
392 // Ensure that the disconnection logic runs only once (instead of on ce per each 422 // Ensure that the disconnection logic runs only once (instead of on ce per each
393 // ChildServiceConnection). 423 // ChildServiceConnection).
394 if (mServiceDisconnected) { 424 if (mServiceDisconnected) {
395 return; 425 return;
396 } 426 }
397 // Stash the status of the oom bindings, since stop() will release a ll bindings.
398 mWasOomProtected = isCurrentlyOomProtected();
399 mServiceDisconnected = true; 427 mServiceDisconnected = true;
400 Log.w(TAG, "onServiceDisconnected (crash or killed by oom): pid=%d", mPid); 428 Log.w(TAG, "onServiceDisconnected (crash or killed by oom): pid=%d", mPid);
401 stop(); // We don't want to auto-restart on crash. Let the browser d o that. 429 stop(); // We don't want to auto-restart on crash. Let the browser d o that.
402 mDeathCallback.onChildProcessDied(ChildProcessConnectionImpl.this); 430 mDeathCallback.onChildProcessDied(BaseChildProcessConnection.this);
403 // If we have a pending connection callback, we need to communicate the failure to 431 // If we have a pending connection callback, we need to communicate the failure to
404 // the caller. 432 // the caller.
405 if (mConnectionCallback != null) { 433 if (mConnectionCallback != null) {
406 mConnectionCallback.onConnected(0); 434 mConnectionCallback.onConnected(null);
407 } 435 }
408 mConnectionCallback = null; 436 mConnectionCallback = null;
409 } 437 }
410 } 438 }
411 439
412 private void onSetupConnectionResult(int pid) { 440 private void onSetupConnectionResult(int pid) {
413 synchronized (mLock) { 441 synchronized (mLock) {
414 mPid = pid; 442 mPid = pid;
415 assert mPid != 0 : "Child service claims to be run by a process of p id=0."; 443 assert mPid != 0 : "Child service claims to be run by a process of p id=0.";
416 444
417 if (mConnectionCallback != null) { 445 if (mConnectionCallback != null) {
418 mConnectionCallback.onConnected(mPid); 446 mConnectionCallback.onConnected(this);
419 } 447 }
420 mConnectionCallback = null; 448 mConnectionCallback = null;
421 } 449 }
422 } 450 }
423 451
424 /** 452 /**
425 * Called after the connection parameters have been set (in setupConnection( )) *and* a 453 * Called after the connection parameters have been set (in setupConnection( )) *and* a
426 * connection has been established (as signaled by onServiceConnected()). Th ese two events can 454 * connection has been established (as signaled by onServiceConnected()). Th ese two events can
427 * happen in any order. Has to be called with mLock. 455 * happen in any order. Has to be called with mLock.
428 */ 456 */
457 @GuardedBy("mLock")
429 private void doConnectionSetupLocked() { 458 private void doConnectionSetupLocked() {
430 try { 459 try {
431 TraceEvent.begin("ChildProcessConnectionImpl.doConnectionSetupLocked "); 460 TraceEvent.begin("BaseChildProcessConnection.doConnectionSetupLocked ");
432 assert mServiceConnectComplete && mService != null; 461 assert mServiceConnectComplete && mService != null;
433 assert mConnectionParams != null; 462 assert mConnectionParams != null;
434 463
435 Bundle bundle = ChildProcessLauncher.createsServiceBundle( 464 Bundle bundle = ChildProcessLauncher.createsServiceBundle(
436 mConnectionParams.mCommandLine, mConnectionParams.mFilesToBe Mapped); 465 mConnectionParams.mCommandLine, mConnectionParams.mFilesToBe Mapped);
437 ICallbackInt pidCallback = new ICallbackInt.Stub() { 466 ICallbackInt pidCallback = new ICallbackInt.Stub() {
438 @Override 467 @Override
439 public void call(final int pid) { 468 public void call(final int pid) {
440 LauncherThread.post(new Runnable() { 469 LauncherThread.post(new Runnable() {
441 @Override 470 @Override
(...skipping 11 matching lines...) Expand all
453 // We proactively close the FDs rather than wait for GC & finalizer. 482 // We proactively close the FDs rather than wait for GC & finalizer.
454 try { 483 try {
455 for (FileDescriptorInfo fileInfo : mConnectionParams.mFilesToBeM apped) { 484 for (FileDescriptorInfo fileInfo : mConnectionParams.mFilesToBeM apped) {
456 fileInfo.fd.close(); 485 fileInfo.fd.close();
457 } 486 }
458 } catch (IOException ioe) { 487 } catch (IOException ioe) {
459 Log.w(TAG, "Failed to close FD.", ioe); 488 Log.w(TAG, "Failed to close FD.", ioe);
460 } 489 }
461 mConnectionParams = null; 490 mConnectionParams = null;
462 } finally { 491 } finally {
463 TraceEvent.end("ChildProcessConnectionImpl.doConnectionSetupLocked") ; 492 TraceEvent.end("BaseChildProcessConnection.doConnectionSetupLocked") ;
464 } 493 }
465 } 494 }
466 495
467 @Override 496 /** Subclasses should implement this method to bind/unbind to the actual ser vice. */
468 public boolean isInitialBindingBound() { 497 protected abstract boolean bind();
469 synchronized (mLock) { 498 protected abstract void unbind();
470 return mInitialBinding.isBound(); 499
471 } 500 protected ChildServiceConnection createServiceConnection(int bindFlags) {
501 return new ChildServiceConnectionImpl(bindFlags);
472 } 502 }
473 503
474 @Override 504 protected boolean shouldBindAsExportedService() {
475 public boolean isStrongBindingBound() { 505 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && getCreationPara ms() != null
476 synchronized (mLock) { 506 && getCreationParams().getIsExternalService()
477 return mStrongBinding.isBound(); 507 && isExportedService(isSandboxed(), getContext(), getServiceName ());
478 }
479 } 508 }
480 509
481 @Override 510 private static boolean isExportedService(
482 public void removeInitialBinding() { 511 boolean inSandbox, Context context, ComponentName serviceName) {
483 synchronized (mLock) { 512 // Check for the cached value first. It is assumed that all pooled child services
484 assert !mAlwaysInForeground; 513 // have identical attributes in the manifest.
485 mInitialBinding.unbind(); 514 final int arrayIndex = inSandbox ? 1 : 0;
515 if (sNeedsExtrabindFlags[arrayIndex] != null) {
516 return sNeedsExtrabindFlags[arrayIndex].booleanValue();
486 } 517 }
518 boolean result = false;
519 try {
520 PackageManager packageManager = context.getPackageManager();
521 ServiceInfo serviceInfo = packageManager.getServiceInfo(serviceName, 0);
522 result = serviceInfo.exported;
523 } catch (PackageManager.NameNotFoundException e) {
524 Log.e(TAG, "Could not retrieve info about service %s", serviceName, e);
525 }
526 sNeedsExtrabindFlags[arrayIndex] = Boolean.valueOf(result);
527 return result;
487 } 528 }
488 529
489 @Override 530 @VisibleForTesting
490 public boolean isOomProtectedOrWasWhenDied() { 531 public void crashServiceForTesting() throws RemoteException {
491 synchronized (mLock) { 532 synchronized (mLock) {
492 if (mServiceDisconnected) { 533 mService.crashIntentionallyForTesting();
493 return mWasOomProtected;
494 } else {
495 return isCurrentlyOomProtected();
496 }
497 }
498 }
499
500 private boolean isCurrentlyOomProtected() {
501 synchronized (mLock) {
502 assert !mServiceDisconnected;
503 if (mAlwaysInForeground) return ChildProcessLauncher.isApplicationIn Foreground();
504 return mInitialBinding.isBound() || mStrongBinding.isBound();
505 }
506 }
507
508 @Override
509 public void dropOomBindings() {
510 synchronized (mLock) {
511 assert !mAlwaysInForeground;
512 mInitialBinding.unbind();
513
514 mStrongBindingCount = 0;
515 mStrongBinding.unbind();
516
517 mModerateBinding.unbind();
518 }
519 }
520
521 @Override
522 public void addStrongBinding() {
523 synchronized (mLock) {
524 if (mService == null) {
525 Log.w(TAG, "The connection is not bound for %d", mPid);
526 return;
527 }
528 if (mStrongBindingCount == 0) {
529 mStrongBinding.bind();
530 }
531 mStrongBindingCount++;
532 }
533 }
534
535 @Override
536 public void removeStrongBinding() {
537 synchronized (mLock) {
538 if (mService == null) {
539 Log.w(TAG, "The connection is not bound for %d", mPid);
540 return;
541 }
542 assert mStrongBindingCount > 0;
543 mStrongBindingCount--;
544 if (mStrongBindingCount == 0) {
545 mStrongBinding.unbind();
546 }
547 }
548 }
549
550 @Override
551 public boolean isModerateBindingBound() {
552 synchronized (mLock) {
553 return mModerateBinding.isBound();
554 }
555 }
556
557 @Override
558 public void addModerateBinding() {
559 synchronized (mLock) {
560 if (mService == null) {
561 Log.w(TAG, "The connection is not bound for %d", mPid);
562 return;
563 }
564 mModerateBinding.bind();
565 }
566 }
567
568 @Override
569 public void removeModerateBinding() {
570 synchronized (mLock) {
571 if (mService == null) {
572 Log.w(TAG, "The connection is not bound for %d", mPid);
573 return;
574 }
575 mModerateBinding.unbind();
576 } 534 }
577 } 535 }
578 536
579 @VisibleForTesting 537 @VisibleForTesting
580 public void crashServiceForTesting() throws RemoteException {
581 mService.crashIntentionallyForTesting();
582 }
583
584 @VisibleForTesting
585 public boolean isConnected() { 538 public boolean isConnected() {
586 return mService != null; 539 synchronized (mLock) {
540 return mService != null;
541 }
587 } 542 }
588 } 543 }
OLDNEW
« no previous file with comments | « content/public/android/BUILD.gn ('k') | content/public/android/java/src/org/chromium/content/browser/BindingManager.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698