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

Side by Side Diff: content/public/android/java/src/org/chromium/content/app/ChildProcessService.java

Issue 2049843004: Upstream: Renderers are running in WebAPKs. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Always check command line flags in getNum(Class)ofService(). Created 4 years, 6 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 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 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.app; 5 package org.chromium.content.app;
6 6
7 import android.app.Service; 7 import android.app.Service;
8 import android.content.Context;
9 import android.content.Intent; 8 import android.content.Intent;
10 import android.graphics.SurfaceTexture;
11 import android.os.Bundle; 9 import android.os.Bundle;
12 import android.os.IBinder; 10 import android.os.IBinder;
13 import android.os.Parcelable;
14 import android.os.Process;
15 import android.os.RemoteException;
16 import android.view.Surface;
17 11
18 import org.chromium.base.BaseSwitches;
19 import org.chromium.base.CommandLine;
20 import org.chromium.base.ContextUtils;
21 import org.chromium.base.Log;
22 import org.chromium.base.annotations.CalledByNative;
23 import org.chromium.base.annotations.JNINamespace; 12 import org.chromium.base.annotations.JNINamespace;
24 import org.chromium.base.annotations.SuppressFBWarnings;
25 import org.chromium.base.library_loader.LibraryLoader;
26 import org.chromium.base.library_loader.Linker;
27 import org.chromium.base.library_loader.ProcessInitException;
28 import org.chromium.content.browser.ChildProcessConstants;
29 import org.chromium.content.browser.ChildProcessCreationParams;
30 import org.chromium.content.browser.ChildProcessLauncher; 13 import org.chromium.content.browser.ChildProcessLauncher;
31 import org.chromium.content.browser.FileDescriptorInfo;
32 import org.chromium.content.common.ContentSwitches;
33 import org.chromium.content.common.IChildProcessCallback;
34 import org.chromium.content.common.IChildProcessService;
35 import org.chromium.content.common.SurfaceWrapper;
36
37 import java.util.concurrent.Semaphore;
38 import java.util.concurrent.atomic.AtomicReference;
39 14
40 /** 15 /**
41 * This is the base class for child services; the [Non]SandboxedProcessService0, 1.. etc 16 * This is the base class for child services; the [Non]SandboxedProcessService0, 1.. etc
42 * subclasses provide the concrete service entry points, to enable the browser t o connect 17 * subclasses provide the concrete service entry points, to enable the browser t o connect
43 * to more than one distinct process (i.e. one process per service number, up to limit of N). 18 * to more than one distinct process (i.e. one process per service number, up to limit of N).
44 * The embedding application must declare these service instances in the applica tion section 19 * The embedding application must declare these service instances in the applica tion section
45 * of its AndroidManifest.xml, for example with N entries of the form:- 20 * of its AndroidManifest.xml, for example with N entries of the form:-
46 * <service android:name="org.chromium.content.app.[Non]SandboxedProcessServ iceX" 21 * <service android:name="org.chromium.content.app.[Non]SandboxedProcessServ iceX"
47 * android:process=":[non]sandboxed_processX" /> 22 * android:process=":[non]sandboxed_processX" />
48 * for X in 0...N-1 (where N is {@link ChildProcessLauncher#MAX_REGISTERED_SERVI CES}) 23 * for X in 0...N-1 (where N is {@link ChildProcessLauncher#MAX_REGISTERED_SERVI CES})
49 */ 24 */
50 @JNINamespace("content") 25 @JNINamespace("content")
51 @SuppressWarnings("SynchronizeOnNonFinalField")
52 public class ChildProcessService extends Service { 26 public class ChildProcessService extends Service {
53 private static final String MAIN_THREAD_NAME = "ChildProcessMain"; 27 private final ChildProcessServiceImpl mChildProcessServiceImpl = new ChildPr ocessServiceImpl();
54 private static final String TAG = "ChildProcessService";
55 protected static final FileDescriptorInfo[] EMPTY_FILE_DESCRIPTOR_INFO = {};
56 private IChildProcessCallback mCallback;
57
58 // This is the native "Main" thread for the renderer / utility process.
59 private Thread mMainThread;
60 // Parameters received via IPC, only accessed while holding the mMainThread monitor.
61 private String[] mCommandLineParams;
62 private int mCpuCount;
63 private long mCpuFeatures;
64 // File descriptors that should be registered natively.
65 private FileDescriptorInfo[] mFdInfos;
66 // Linker-specific parameters for this child process service.
67 private ChromiumLinkerParams mLinkerParams;
68 // Child library process type.
69 private int mLibraryProcessType;
70
71 private static AtomicReference<Context> sContext = new AtomicReference<Conte xt>(null);
72 private boolean mLibraryInitialized = false;
73 // Becomes true once the service is bound. Access must synchronize around mM ainThread.
74 private boolean mIsBound = false;
75
76 private final Semaphore mActivitySemaphore = new Semaphore(1);
77
78 // Return a Linker instance. If testing, the Linker needs special setup.
79 private Linker getLinker() {
80 if (Linker.areTestsEnabled()) {
81 // For testing, set the Linker implementation and the test runner
82 // class name to match those used by the parent.
83 assert mLinkerParams != null;
84 Linker.setupForTesting(
85 mLinkerParams.mLinkerImplementationForTesting,
86 mLinkerParams.mTestRunnerClassNameForTesting);
87 }
88 return Linker.getInstance();
89 }
90
91 // Binder object used by clients for this service.
92 private final IChildProcessService.Stub mBinder = new IChildProcessService.S tub() {
93 // NOTE: Implement any IChildProcessService methods here.
94 @Override
95 public int setupConnection(Bundle args, IChildProcessCallback callback) {
96 mCallback = callback;
97 getServiceInfo(args);
98 return Process.myPid();
99 }
100
101 @Override
102 public void crashIntentionallyForTesting() {
103 Process.killProcess(Process.myPid());
104 }
105 };
106 28
107 @Override 29 @Override
108 public void onCreate() { 30 public void onCreate() {
109 Log.i(TAG, "Creating new ChildProcessService pid=%d", Process.myPid());
110 if (sContext.get() != null) {
111 throw new RuntimeException("Illegal child process reuse.");
112 }
113 sContext.set(this);
114 super.onCreate(); 31 super.onCreate();
115 32 mChildProcessServiceImpl.create(getApplicationContext(),
116 ContextUtils.initApplicationContext(getApplicationContext()); 33 getApplicationContext());
117
118 mMainThread = new Thread(new Runnable() {
119 @Override
120 @SuppressFBWarnings("DM_EXIT")
121 public void run() {
122 try {
123 // CommandLine must be initialized before everything else.
124 synchronized (mMainThread) {
125 while (mCommandLineParams == null) {
126 mMainThread.wait();
127 }
128 }
129 CommandLine.init(mCommandLineParams);
130
131 Linker linker = null;
132 boolean requestedSharedRelro = false;
133 if (Linker.isUsed()) {
134 synchronized (mMainThread) {
135 while (!mIsBound) {
136 mMainThread.wait();
137 }
138 }
139 linker = getLinker();
140 if (mLinkerParams.mWaitForSharedRelro) {
141 requestedSharedRelro = true;
142 linker.initServiceProcess(mLinkerParams.mBaseLoadAdd ress);
143 } else {
144 linker.disableSharedRelros();
145 }
146 }
147 boolean isLoaded = false;
148 if (CommandLine.getInstance().hasSwitch(
149 BaseSwitches.RENDERER_WAIT_FOR_JAVA_DEBUGGER)) {
150 android.os.Debug.waitForDebugger();
151 }
152
153 boolean loadAtFixedAddressFailed = false;
154 try {
155 LibraryLoader.get(mLibraryProcessType).loadNow(getApplic ationContext());
156 isLoaded = true;
157 } catch (ProcessInitException e) {
158 if (requestedSharedRelro) {
159 Log.w(TAG, "Failed to load native library with share d RELRO, "
160 + "retrying without");
161 loadAtFixedAddressFailed = true;
162 } else {
163 Log.e(TAG, "Failed to load native library", e);
164 }
165 }
166 if (!isLoaded && requestedSharedRelro) {
167 linker.disableSharedRelros();
168 try {
169 LibraryLoader.get(mLibraryProcessType).loadNow(getAp plicationContext());
170 isLoaded = true;
171 } catch (ProcessInitException e) {
172 Log.e(TAG, "Failed to load native library on retry", e);
173 }
174 }
175 if (!isLoaded) {
176 System.exit(-1);
177 }
178 LibraryLoader.get(mLibraryProcessType)
179 .registerRendererProcessHistogram(requestedSharedRel ro,
180 loadAtFixedAddressFailed);
181 LibraryLoader.get(mLibraryProcessType).initialize();
182 synchronized (mMainThread) {
183 mLibraryInitialized = true;
184 mMainThread.notifyAll();
185 while (mFdInfos == null) {
186 mMainThread.wait();
187 }
188 }
189 for (FileDescriptorInfo fdInfo : mFdInfos) {
190 nativeRegisterGlobalFileDescriptor(
191 fdInfo.mId, fdInfo.mFd.detachFd(), fdInfo.mOffse t, fdInfo.mSize);
192 }
193 nativeInitChildProcess(ChildProcessService.this, mCpuCount, mCpuFeatures);
194 if (mActivitySemaphore.tryAcquire()) {
195 ContentMain.start();
196 nativeExitChildProcess();
197 }
198 } catch (InterruptedException e) {
199 Log.w(TAG, "%s startup failed: %s", MAIN_THREAD_NAME, e);
200 } catch (ProcessInitException e) {
201 Log.w(TAG, "%s startup failed: %s", MAIN_THREAD_NAME, e);
202 }
203 }
204 }, MAIN_THREAD_NAME);
205 mMainThread.start();
206 } 34 }
207 35
208 @Override 36 @Override
209 @SuppressFBWarnings("DM_EXIT")
210 public void onDestroy() { 37 public void onDestroy() {
211 Log.i(TAG, "Destroying ChildProcessService pid=%d", Process.myPid());
212 super.onDestroy(); 38 super.onDestroy();
213 if (mActivitySemaphore.tryAcquire()) { 39 mChildProcessServiceImpl.destroy();
214 // TODO(crbug.com/457406): This is a bit hacky, but there is no know n better solution
215 // as this service will get reused (at least if not sandboxed).
216 // In fact, we might really want to always exit() from onDestroy(), not just from
217 // the early return here.
218 System.exit(0);
219 return;
220 }
221 synchronized (mMainThread) {
222 try {
223 while (!mLibraryInitialized) {
224 // Avoid a potential race in calling through to native code before the library
225 // has loaded.
226 mMainThread.wait();
227 }
228 } catch (InterruptedException e) {
229 // Ignore
230 }
231 }
232 // Try to shutdown the MainThread gracefully, but it might not
233 // have chance to exit normally.
234 nativeShutdownMainThread();
235 } 40 }
236 41
237 @Override 42 @Override
238 public IBinder onBind(Intent intent) { 43 public IBinder onBind(Intent intent) {
239 // We call stopSelf() to request that this service be stopped as soon as the client 44 // We call stopSelf() to request that this service be stopped as soon as the client
240 // unbinds. Otherwise the system may keep it around and available for a reconnect. The 45 // unbinds. Otherwise the system may keep it around and available for a reconnect. The
241 // child processes do not currently support reconnect; they must be init ialized from 46 // child processes do not currently support reconnect; they must be init ialized from
242 // scratch every time. 47 // scratch every time.
243 stopSelf(); 48 stopSelf();
244 initializeParams(intent); 49 return mChildProcessServiceImpl.bind(intent);
245 return mBinder;
246 } 50 }
247 51
248 /** 52 /**
249 * Helper method to initialize the params from intent. 53 * Helper method to initialize the params from intent.
250 * @param intent Intent to launch the service. 54 * @param intent Intent to launch the service.
251 */ 55 */
252 protected void initializeParams(Intent intent) { 56 protected void initializeParams(Intent intent) {
253 synchronized (mMainThread) { 57 mChildProcessServiceImpl.initializeParams(intent);
254 mCommandLineParams =
255 intent.getStringArrayExtra(ChildProcessConstants.EXTRA_COMMA ND_LINE);
256 // mLinkerParams is never used if Linker.isUsed() returns false.
257 // See onCreate().
258 mLinkerParams = new ChromiumLinkerParams(intent);
259 mLibraryProcessType = ChildProcessCreationParams.getLibraryProcessTy pe(intent);
260 mIsBound = true;
261 mMainThread.notifyAll();
262 }
263 } 58 }
264 59
265 /** 60 /**
266 * Helper method to get the information about the service from a given bundl e. 61 * Helper method to get the information about the service from a given bundl e.
267 * @param bundle Bundle that contains the information to start the service. 62 * @param bundle Bundle that contains the information to start the service.
268 */ 63 */
269 void getServiceInfo(Bundle bundle) { 64 protected void getServiceInfo(Bundle bundle) {
270 // Required to unparcel FileDescriptorInfo. 65 mChildProcessServiceImpl.getServiceInfo(bundle);
271 bundle.setClassLoader(getClassLoader());
272 synchronized (mMainThread) {
273 // Allow the command line to be set via bind() intent or setupConnec tion, but
274 // the FD can only be transferred here.
275 if (mCommandLineParams == null) {
276 mCommandLineParams =
277 bundle.getStringArray(ChildProcessConstants.EXTRA_COMMAN D_LINE);
278 }
279 // We must have received the command line by now
280 assert mCommandLineParams != null;
281 mCpuCount = bundle.getInt(ChildProcessConstants.EXTRA_CPU_COUNT);
282 mCpuFeatures = bundle.getLong(ChildProcessConstants.EXTRA_CPU_FEATUR ES);
283 assert mCpuCount > 0;
284 Parcelable[] fdInfosAsParcelable =
285 bundle.getParcelableArray(ChildProcessConstants.EXTRA_FILES) ;
286 if (fdInfosAsParcelable != null) {
287 // For why this arraycopy is necessary:
288 // http://stackoverflow.com/questions/8745893/i-dont-get-why-thi s-classcastexception-occurs
289 mFdInfos = new FileDescriptorInfo[fdInfosAsParcelable.length];
290 System.arraycopy(fdInfosAsParcelable, 0, mFdInfos, 0, fdInfosAsP arcelable.length);
291 } else {
292 String processType = ContentSwitches.getSwitchValue(
293 mCommandLineParams, ContentSwitches.SWITCH_PROCESS_TYPE) ;
294 assert ContentSwitches.SWITCH_DOWNLOAD_PROCESS.equals(processTyp e);
295 mFdInfos = EMPTY_FILE_DESCRIPTOR_INFO;
296 }
297 Bundle sharedRelros = bundle.getBundle(Linker.EXTRA_LINKER_SHARED_RE LROS);
298 if (sharedRelros != null) {
299 getLinker().useSharedRelros(sharedRelros);
300 sharedRelros = null;
301 }
302 mMainThread.notifyAll();
303 }
304 } 66 }
305
306 /**
307 * Called from native code to share a surface texture with another child pro cess.
308 * Through using the callback object the browser is used as a proxy to route the
309 * call to the correct process.
310 *
311 * @param pid Process handle of the child process to share the SurfaceTextur e with.
312 * @param surfaceObject The Surface or SurfaceTexture to share with the othe r child process.
313 * @param primaryID Used to route the call to the correct client instance.
314 * @param secondaryID Used to route the call to the correct client instance.
315 */
316 @SuppressWarnings("unused")
317 @CalledByNative
318 private void establishSurfaceTexturePeer(
319 int pid, Object surfaceObject, int primaryID, int secondaryID) {
320 if (mCallback == null) {
321 Log.e(TAG, "No callback interface has been provided.");
322 return;
323 }
324
325 Surface surface = null;
326 boolean needRelease = false;
327 if (surfaceObject instanceof Surface) {
328 surface = (Surface) surfaceObject;
329 } else if (surfaceObject instanceof SurfaceTexture) {
330 surface = new Surface((SurfaceTexture) surfaceObject);
331 needRelease = true;
332 } else {
333 Log.e(TAG, "Not a valid surfaceObject: %s", surfaceObject);
334 return;
335 }
336 try {
337 mCallback.establishSurfacePeer(pid, surface, primaryID, secondaryID) ;
338 } catch (RemoteException e) {
339 Log.e(TAG, "Unable to call establishSurfaceTexturePeer: %s", e);
340 return;
341 } finally {
342 if (needRelease) {
343 surface.release();
344 }
345 }
346 }
347
348 @SuppressWarnings("unused")
349 @CalledByNative
350 private Surface getViewSurface(int surfaceId) {
351 if (mCallback == null) {
352 Log.e(TAG, "No callback interface has been provided.");
353 return null;
354 }
355
356 try {
357 SurfaceWrapper wrapper = mCallback.getViewSurface(surfaceId);
358 return wrapper != null ? wrapper.getSurface() : null;
359 } catch (RemoteException e) {
360 Log.e(TAG, "Unable to call getViewSurface: %s", e);
361 return null;
362 }
363 }
364
365 @SuppressWarnings("unused")
366 @CalledByNative
367 private void createSurfaceTextureSurface(
368 int surfaceTextureId, int clientId, SurfaceTexture surfaceTexture) {
369 if (mCallback == null) {
370 Log.e(TAG, "No callback interface has been provided.");
371 return;
372 }
373
374 Surface surface = new Surface(surfaceTexture);
375 try {
376 mCallback.registerSurfaceTextureSurface(surfaceTextureId, clientId, surface);
377 } catch (RemoteException e) {
378 Log.e(TAG, "Unable to call registerSurfaceTextureSurface: %s", e);
379 }
380 surface.release();
381 }
382
383 @SuppressWarnings("unused")
384 @CalledByNative
385 private void destroySurfaceTextureSurface(int surfaceTextureId, int clientId ) {
386 if (mCallback == null) {
387 Log.e(TAG, "No callback interface has been provided.");
388 return;
389 }
390
391 try {
392 mCallback.unregisterSurfaceTextureSurface(surfaceTextureId, clientId );
393 } catch (RemoteException e) {
394 Log.e(TAG, "Unable to call unregisterSurfaceTextureSurface: %s", e);
395 }
396 }
397
398 @SuppressWarnings("unused")
399 @CalledByNative
400 private Surface getSurfaceTextureSurface(int surfaceTextureId) {
401 if (mCallback == null) {
402 Log.e(TAG, "No callback interface has been provided.");
403 return null;
404 }
405
406 try {
407 return mCallback.getSurfaceTextureSurface(surfaceTextureId).getSurfa ce();
408 } catch (RemoteException e) {
409 Log.e(TAG, "Unable to call getSurfaceTextureSurface: %s", e);
410 return null;
411 }
412 }
413
414 /**
415 * Helper for registering FileDescriptorInfo objects with GlobalFileDescript ors.
416 * This includes the IPC channel, the crash dump signals and resource relate d
417 * files.
418 */
419 private static native void nativeRegisterGlobalFileDescriptor(
420 int id, int fd, long offset, long size);
421
422 /**
423 * The main entry point for a child process. This should be called from a ne w thread since
424 * it will not return until the child process exits. See child_process_servi ce.{h,cc}
425 *
426 * @param service The current ChildProcessService object.
427 * renderer.
428 */
429 private static native void nativeInitChildProcess(
430 ChildProcessService service, int cpuCount, long cpuFeatures);
431
432 /**
433 * Force the child process to exit.
434 */
435 private static native void nativeExitChildProcess();
436
437 private native void nativeShutdownMainThread();
438 } 67 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698