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

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

Powered by Google App Engine
This is Rietveld 408576698