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

Side by Side Diff: content/public/android/java/src/org/chromium/content/app/ChildProcessServiceImpl.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 2016 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;
8 import android.content.Context; 7 import android.content.Context;
9 import android.content.Intent; 8 import android.content.Intent;
10 import android.graphics.SurfaceTexture; 9 import android.graphics.SurfaceTexture;
11 import android.os.Bundle; 10 import android.os.Bundle;
12 import android.os.IBinder; 11 import android.os.IBinder;
13 import android.os.Parcelable; 12 import android.os.Parcelable;
14 import android.os.Process; 13 import android.os.Process;
15 import android.os.RemoteException; 14 import android.os.RemoteException;
16 import android.view.Surface; 15 import android.view.Surface;
17 16
18 import org.chromium.base.BaseSwitches; 17 import org.chromium.base.BaseSwitches;
19 import org.chromium.base.CommandLine; 18 import org.chromium.base.CommandLine;
20 import org.chromium.base.ContextUtils; 19 import org.chromium.base.ContextUtils;
21 import org.chromium.base.Log; 20 import org.chromium.base.Log;
22 import org.chromium.base.annotations.CalledByNative; 21 import org.chromium.base.annotations.CalledByNative;
23 import org.chromium.base.annotations.JNINamespace; 22 import org.chromium.base.annotations.JNINamespace;
24 import org.chromium.base.annotations.SuppressFBWarnings; 23 import org.chromium.base.annotations.SuppressFBWarnings;
25 import org.chromium.base.library_loader.LibraryLoader; 24 import org.chromium.base.library_loader.LibraryLoader;
26 import org.chromium.base.library_loader.Linker; 25 import org.chromium.base.library_loader.Linker;
27 import org.chromium.base.library_loader.ProcessInitException; 26 import org.chromium.base.library_loader.ProcessInitException;
28 import org.chromium.content.browser.ChildProcessConstants; 27 import org.chromium.content.browser.ChildProcessConstants;
29 import org.chromium.content.browser.ChildProcessCreationParams; 28 import org.chromium.content.browser.ChildProcessCreationParams;
30 import org.chromium.content.browser.ChildProcessLauncher;
31 import org.chromium.content.browser.FileDescriptorInfo; 29 import org.chromium.content.browser.FileDescriptorInfo;
32 import org.chromium.content.common.ContentSwitches; 30 import org.chromium.content.common.ContentSwitches;
33 import org.chromium.content.common.IChildProcessCallback; 31 import org.chromium.content.common.IChildProcessCallback;
34 import org.chromium.content.common.IChildProcessService; 32 import org.chromium.content.common.IChildProcessService;
35 import org.chromium.content.common.SurfaceWrapper; 33 import org.chromium.content.common.SurfaceWrapper;
36 34
37 import java.util.concurrent.Semaphore; 35 import java.util.concurrent.Semaphore;
38 import java.util.concurrent.atomic.AtomicReference; 36 import java.util.concurrent.atomic.AtomicReference;
39 37
40 /** 38 /**
41 * This is the base class for child services; the [Non]SandboxedProcessService0, 1.. etc 39 * This class provides all the implementations for {@link ChildProcessService} w hich owns an
42 * subclasses provide the concrete service entry points, to enable the browser t o connect 40 * object of {@link ChildProcessServiceImpl}.
43 * to more than one distinct process (i.e. one process per service number, up to limit of N). 41 * It makes possible that WebAPK's ChildProcessService owns a ChildProcessServic eImpl object
44 * The embedding application must declare these service instances in the applica tion section 42 * and uses the same functionalities to create renderer process for WebAPKs when "--enable-webapk"
45 * of its AndroidManifest.xml, for example with N entries of the form:- 43 * flag is turned on.
46 * <service android:name="org.chromium.content.app.[Non]SandboxedProcessServ iceX"
47 * android:process=":[non]sandboxed_processX" />
48 * for X in 0...N-1 (where N is {@link ChildProcessLauncher#MAX_REGISTERED_SERVI CES})
49 */ 44 */
50 @JNINamespace("content") 45 @JNINamespace("content")
51 @SuppressWarnings("SynchronizeOnNonFinalField") 46 @SuppressWarnings("SynchronizeOnNonFinalField")
52 public class ChildProcessService extends Service { 47 public class ChildProcessServiceImpl {
53 private static final String MAIN_THREAD_NAME = "ChildProcessMain"; 48 private static final String MAIN_THREAD_NAME = "ChildProcessMain";
54 private static final String TAG = "ChildProcessService"; 49 private static final String TAG = "ChildProcessService";
55 protected static final FileDescriptorInfo[] EMPTY_FILE_DESCRIPTOR_INFO = {}; 50 protected static final FileDescriptorInfo[] EMPTY_FILE_DESCRIPTOR_INFO = {};
56 private IChildProcessCallback mCallback; 51 private IChildProcessCallback mCallback;
57 52
58 // This is the native "Main" thread for the renderer / utility process. 53 // This is the native "Main" thread for the renderer / utility process.
59 private Thread mMainThread; 54 private Thread mMainThread;
60 // Parameters received via IPC, only accessed while holding the mMainThread monitor. 55 // Parameters received via IPC, only accessed while holding the mMainThread monitor.
61 private String[] mCommandLineParams; 56 private String[] mCommandLineParams;
62 private int mCpuCount; 57 private int mCpuCount;
63 private long mCpuFeatures; 58 private long mCpuFeatures;
64 // File descriptors that should be registered natively. 59 // File descriptors that should be registered natively.
65 private FileDescriptorInfo[] mFdInfos; 60 private FileDescriptorInfo[] mFdInfos;
66 // Linker-specific parameters for this child process service. 61 // Linker-specific parameters for this child process service.
67 private ChromiumLinkerParams mLinkerParams; 62 private ChromiumLinkerParams mLinkerParams;
68 // Child library process type. 63 // Child library process type.
69 private int mLibraryProcessType; 64 private int mLibraryProcessType;
70 65
71 private static AtomicReference<Context> sContext = new AtomicReference<Conte xt>(null); 66 private static AtomicReference<Context> sContext = new AtomicReference<Conte xt>(null);
72 private boolean mLibraryInitialized = false; 67 private boolean mLibraryInitialized = false;
73 // Becomes true once the service is bound. Access must synchronize around mM ainThread. 68 // Becomes true once the service is bound. Access must synchronize around mM ainThread.
74 private boolean mIsBound = false; 69 private boolean mIsBound = false;
75 70
76 private final Semaphore mActivitySemaphore = new Semaphore(1); 71 private final Semaphore mActivitySemaphore = new Semaphore(1);
72 private final IChildProcessService.Stub mBinder;
73 private ClassLoader mClassLoader;
77 74
78 // Return a Linker instance. If testing, the Linker needs special setup. 75 // Return a Linker instance. If testing, the Linker needs special setup.
79 private Linker getLinker() { 76 private Linker getLinker() {
80 if (Linker.areTestsEnabled()) { 77 if (Linker.areTestsEnabled()) {
81 // For testing, set the Linker implementation and the test runner 78 // For testing, set the Linker implementation and the test runner
82 // class name to match those used by the parent. 79 // class name to match those used by the parent.
83 assert mLinkerParams != null; 80 assert mLinkerParams != null;
84 Linker.setupForTesting( 81 Linker.setupForTesting(
85 mLinkerParams.mLinkerImplementationForTesting, 82 mLinkerParams.mLinkerImplementationForTesting,
86 mLinkerParams.mTestRunnerClassNameForTesting); 83 mLinkerParams.mTestRunnerClassNameForTesting);
87 } 84 }
88 return Linker.getInstance(); 85 return Linker.getInstance();
89 } 86 }
90 87
91 // Binder object used by clients for this service.
pkotwicz 2016/06/10 21:29:48 Why this change? I tried reverting this change and
Xi Han 2016/06/13 20:04:11 Good catch. I made this changes before introducing
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() { 88 /* package */ static Context getContext() {
108 return sContext.get(); 89 return sContext.get();
109 } 90 }
110 91
111 @Override 92 public ChildProcessServiceImpl() {
112 public void onCreate() { 93 super();
94 mBinder = new IChildProcessService.Stub() {
95 // NOTE: Implement any IChildProcessService methods here.
96 @Override
97 public int setupConnection(Bundle args, IChildProcessCallback callba ck) {
98 mCallback = callback;
99 getServiceInfo(args);
100 return Process.myPid();
101 }
102
103 @Override
104 public void crashIntentionallyForTesting() {
105 Process.killProcess(Process.myPid());
106 }
107 };
108 }
109
pkotwicz 2016/06/10 21:29:48 📚 Please document this method.
Xi Han 2016/06/13 20:04:11 Done.
110 public void create(final Context context, final Context hostBrowserContext,
111 ClassLoader classLoader) {
112 //Debug.waitForDebugger();
pkotwicz 2016/06/10 21:29:47 😁
Xi Han 2016/06/13 20:04:11 Missed this, removed.
113 Log.i(TAG, "Creating new ChildProcessService pid=%d", Process.myPid()); 113 Log.i(TAG, "Creating new ChildProcessService pid=%d", Process.myPid());
114 if (sContext.get() != null) { 114 if (sContext.get() != null) {
115 throw new RuntimeException("Illegal child process reuse."); 115 throw new RuntimeException("Illegal child process reuse.");
116 } 116 }
117 sContext.set(this); 117 sContext.set(context);
118 super.onCreate();
119 118
120 ContextUtils.initApplicationContext(getApplicationContext()); 119 ContextUtils.initApplicationContext(context);
120 mClassLoader = classLoader;
pkotwicz 2016/06/10 21:29:48 Nit: initialize |mClassLoader| at the top of the m
Xi Han 2016/06/13 20:04:11 Done.
121 final ChildProcessServiceImpl instance = this;
pkotwicz 2016/06/10 21:29:47 Remove line 121. You can use ChildProcessServiceIm
Xi Han 2016/06/13 20:04:11 Good to know, thanks!
121 122
122 mMainThread = new Thread(new Runnable() { 123 mMainThread = new Thread(new Runnable() {
123 @Override 124 @Override
124 @SuppressFBWarnings("DM_EXIT") 125 @SuppressFBWarnings("DM_EXIT")
125 public void run() { 126 public void run() {
126 try { 127 try {
127 // CommandLine must be initialized before everything else. 128 // CommandLine must be initialized before everything else.
128 synchronized (mMainThread) { 129 synchronized (mMainThread) {
129 while (mCommandLineParams == null) { 130 while (mCommandLineParams == null) {
130 mMainThread.wait(); 131 mMainThread.wait();
(...skipping 18 matching lines...) Expand all
149 } 150 }
150 } 151 }
151 boolean isLoaded = false; 152 boolean isLoaded = false;
152 if (CommandLine.getInstance().hasSwitch( 153 if (CommandLine.getInstance().hasSwitch(
153 BaseSwitches.RENDERER_WAIT_FOR_JAVA_DEBUGGER)) { 154 BaseSwitches.RENDERER_WAIT_FOR_JAVA_DEBUGGER)) {
154 android.os.Debug.waitForDebugger(); 155 android.os.Debug.waitForDebugger();
155 } 156 }
156 157
157 boolean loadAtFixedAddressFailed = false; 158 boolean loadAtFixedAddressFailed = false;
158 try { 159 try {
159 LibraryLoader.get(mLibraryProcessType).loadNow(getApplic ationContext()); 160 LibraryLoader.get(mLibraryProcessType).loadNow(hostBrows erContext);
160 isLoaded = true; 161 isLoaded = true;
161 } catch (ProcessInitException e) { 162 } catch (ProcessInitException e) {
162 if (requestedSharedRelro) { 163 if (requestedSharedRelro) {
163 Log.w(TAG, "Failed to load native library with share d RELRO, " 164 Log.w(TAG, "Failed to load native library with share d RELRO, "
164 + "retrying without"); 165 + "retrying without");
165 loadAtFixedAddressFailed = true; 166 loadAtFixedAddressFailed = true;
166 } else { 167 } else {
167 Log.e(TAG, "Failed to load native library", e); 168 Log.e(TAG, "Failed to load native library", e);
168 } 169 }
169 } 170 }
170 if (!isLoaded && requestedSharedRelro) { 171 if (!isLoaded && requestedSharedRelro) {
171 linker.disableSharedRelros(); 172 linker.disableSharedRelros();
172 try { 173 try {
173 LibraryLoader.get(mLibraryProcessType).loadNow(getAp plicationContext()); 174 LibraryLoader.get(mLibraryProcessType).loadNow(conte xt);
174 isLoaded = true; 175 isLoaded = true;
175 } catch (ProcessInitException e) { 176 } catch (ProcessInitException e) {
176 Log.e(TAG, "Failed to load native library on retry", e); 177 Log.e(TAG, "Failed to load native library on retry", e);
177 } 178 }
178 } 179 }
179 if (!isLoaded) { 180 if (!isLoaded) {
180 System.exit(-1); 181 System.exit(-1);
181 } 182 }
182 LibraryLoader.get(mLibraryProcessType) 183 LibraryLoader.get(mLibraryProcessType)
183 .registerRendererProcessHistogram(requestedSharedRel ro, 184 .registerRendererProcessHistogram(requestedSharedRel ro,
184 loadAtFixedAddressFailed); 185 loadAtFixedAddressFailed);
185 LibraryLoader.get(mLibraryProcessType).initialize(); 186 LibraryLoader.get(mLibraryProcessType).initialize();
186 synchronized (mMainThread) { 187 synchronized (mMainThread) {
187 mLibraryInitialized = true; 188 mLibraryInitialized = true;
188 mMainThread.notifyAll(); 189 mMainThread.notifyAll();
189 while (mFdInfos == null) { 190 while (mFdInfos == null) {
190 mMainThread.wait(); 191 mMainThread.wait();
191 } 192 }
192 } 193 }
193 for (FileDescriptorInfo fdInfo : mFdInfos) { 194 for (FileDescriptorInfo fdInfo : mFdInfos) {
194 nativeRegisterGlobalFileDescriptor( 195 nativeRegisterGlobalFileDescriptor(
195 fdInfo.mId, fdInfo.mFd.detachFd(), fdInfo.mOffse t, fdInfo.mSize); 196 fdInfo.mId, fdInfo.mFd.detachFd(), fdInfo.mOffse t, fdInfo.mSize);
196 } 197 }
197 nativeInitChildProcess(ChildProcessService.this, mCpuCount, mCpuFeatures); 198 nativeInitChildProcessImpl(instance, mCpuCount, mCpuFeatures );
198 if (mActivitySemaphore.tryAcquire()) { 199 if (mActivitySemaphore.tryAcquire()) {
199 ContentMain.start(); 200 ContentMain.start();
200 nativeExitChildProcess(); 201 nativeExitChildProcess();
201 } 202 }
202 } catch (InterruptedException e) { 203 } catch (InterruptedException e) {
203 Log.w(TAG, "%s startup failed: %s", MAIN_THREAD_NAME, e); 204 Log.w(TAG, "%s startup failed: %s", MAIN_THREAD_NAME, e);
204 } catch (ProcessInitException e) { 205 } catch (ProcessInitException e) {
205 Log.w(TAG, "%s startup failed: %s", MAIN_THREAD_NAME, e); 206 Log.w(TAG, "%s startup failed: %s", MAIN_THREAD_NAME, e);
206 } 207 }
207 } 208 }
208 }, MAIN_THREAD_NAME); 209 }, MAIN_THREAD_NAME);
209 mMainThread.start(); 210 mMainThread.start();
211 Log.d(TAG, "mMainThread is started: %s", mMainThread.getName());
pkotwicz 2016/06/10 21:29:47 Log.i() to match the remainder of the file?
Xi Han 2016/06/13 20:04:11 Sorry, it was debugging log, removed.
210 } 212 }
211 213
212 @Override
213 @SuppressFBWarnings("DM_EXIT") 214 @SuppressFBWarnings("DM_EXIT")
214 public void onDestroy() { 215 public void destroy() {
215 Log.i(TAG, "Destroying ChildProcessService pid=%d", Process.myPid()); 216 Log.i(TAG, "Destroying ChildProcessService pid=%d", Process.myPid());
216 super.onDestroy();
217 if (mActivitySemaphore.tryAcquire()) { 217 if (mActivitySemaphore.tryAcquire()) {
218 // TODO(crbug.com/457406): This is a bit hacky, but there is no know n better solution 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). 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 220 // In fact, we might really want to always exit() from onDestroy(), not just from
221 // the early return here. 221 // the early return here.
222 System.exit(0); 222 System.exit(0);
223 return; 223 return;
224 } 224 }
225 synchronized (mMainThread) { 225 synchronized (mMainThread) {
226 try { 226 try {
227 while (!mLibraryInitialized) { 227 while (!mLibraryInitialized) {
228 // Avoid a potential race in calling through to native code before the library 228 // Avoid a potential race in calling through to native code before the library
229 // has loaded. 229 // has loaded.
230 mMainThread.wait(); 230 mMainThread.wait();
231 } 231 }
232 } catch (InterruptedException e) { 232 } catch (InterruptedException e) {
233 // Ignore 233 // Ignore
234 } 234 }
235 } 235 }
236 // Try to shutdown the MainThread gracefully, but it might not 236 // Try to shutdown the MainThread gracefully, but it might not
237 // have chance to exit normally. 237 // have chance to exit normally.
238 nativeShutdownMainThread(); 238 nativeShutdownMainThread();
239 } 239 }
240 240
241 @Override 241 public IBinder bind(Intent intent) {
242 public IBinder onBind(Intent intent) {
243 // We call stopSelf() to request that this service be stopped as soon as the client 242 // 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 243 // 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 244 // child processes do not currently support reconnect; they must be init ialized from
246 // scratch every time. 245 // scratch every time.
pkotwicz 2016/06/10 21:29:47 Nit: Remove the comment w.r.t to stopSelf()
Xi Han 2016/06/13 20:04:11 Done.
247 stopSelf();
248 initializeParams(intent); 246 initializeParams(intent);
249 return mBinder; 247 return mBinder;
250 } 248 }
251 249
252 /** 250 /**
253 * Helper method to initialize the params from intent. 251 * Helper method to initialize the params from intent.
254 * @param intent Intent to launch the service. 252 * @param intent Intent to launch the service.
255 */ 253 */
256 protected void initializeParams(Intent intent) { 254 protected void initializeParams(Intent intent) {
257 synchronized (mMainThread) { 255 synchronized (mMainThread) {
258 mCommandLineParams = 256 mCommandLineParams =
259 intent.getStringArrayExtra(ChildProcessConstants.EXTRA_COMMA ND_LINE); 257 intent.getStringArrayExtra(ChildProcessConstants.EXTRA_COMMA ND_LINE);
260 // mLinkerParams is never used if Linker.isUsed() returns false. 258 // mLinkerParams is never used if Linker.isUsed() returns false.
261 // See onCreate(). 259 // See onCreate().
262 mLinkerParams = new ChromiumLinkerParams(intent); 260 mLinkerParams = new ChromiumLinkerParams(intent);
263 mLibraryProcessType = ChildProcessCreationParams.getLibraryProcessTy pe(intent); 261 mLibraryProcessType = ChildProcessCreationParams.getLibraryProcessTy pe(intent);
264 mIsBound = true; 262 mIsBound = true;
265 mMainThread.notifyAll(); 263 mMainThread.notifyAll();
266 } 264 }
267 } 265 }
268 266
269 /** 267 /**
270 * Helper method to get the information about the service from a given bundl e. 268 * 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. 269 * @param bundle Bundle that contains the information to start the service.
272 */ 270 */
273 void getServiceInfo(Bundle bundle) { 271 void getServiceInfo(Bundle bundle) {
274 // Required to unparcel FileDescriptorInfo. 272 // Required to unparcel FileDescriptorInfo.
275 bundle.setClassLoader(getClassLoader()); 273 bundle.setClassLoader(mClassLoader);
276 synchronized (mMainThread) { 274 synchronized (mMainThread) {
277 // Allow the command line to be set via bind() intent or setupConnec tion, but 275 // Allow the command line to be set via bind() intent or setupConnec tion, but
278 // the FD can only be transferred here. 276 // the FD can only be transferred here.
279 if (mCommandLineParams == null) { 277 if (mCommandLineParams == null) {
280 mCommandLineParams = 278 mCommandLineParams =
281 bundle.getStringArray(ChildProcessConstants.EXTRA_COMMAN D_LINE); 279 bundle.getStringArray(ChildProcessConstants.EXTRA_COMMAN D_LINE);
282 } 280 }
283 // We must have received the command line by now 281 // We must have received the command line by now
284 assert mCommandLineParams != null; 282 assert mCommandLineParams != null;
285 mCpuCount = bundle.getInt(ChildProcessConstants.EXTRA_CPU_COUNT); 283 mCpuCount = bundle.getInt(ChildProcessConstants.EXTRA_CPU_COUNT);
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
420 * This includes the IPC channel, the crash dump signals and resource relate d 418 * This includes the IPC channel, the crash dump signals and resource relate d
421 * files. 419 * files.
422 */ 420 */
423 private static native void nativeRegisterGlobalFileDescriptor( 421 private static native void nativeRegisterGlobalFileDescriptor(
424 int id, int fd, long offset, long size); 422 int id, int fd, long offset, long size);
425 423
426 /** 424 /**
427 * The main entry point for a child process. This should be called from a ne w thread since 425 * 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} 426 * it will not return until the child process exits. See child_process_servi ce.{h,cc}
429 * 427 *
430 * @param service The current ChildProcessService object. 428 * @param serviceImpl The current ChildProcessServiceImpl object.
431 * renderer. 429 * renderer.
432 */ 430 */
433 private static native void nativeInitChildProcess( 431 private static native void nativeInitChildProcessImpl(
434 ChildProcessService service, int cpuCount, long cpuFeatures); 432 ChildProcessServiceImpl serviceImpl, int cpuCount, long cpuFeatures) ;
435 433
436 /** 434 /**
437 * Force the child process to exit. 435 * Force the child process to exit.
438 */ 436 */
439 private static native void nativeExitChildProcess(); 437 private static native void nativeExitChildProcess();
440 438
441 private native void nativeShutdownMainThread(); 439 private native void nativeShutdownMainThread();
442 } 440 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698