OLD | NEW |
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 implements all of the functionality for {@link ChildProcessService
} which 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; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 getServiceInfo(args); | 92 getServiceInfo(args); |
98 return Process.myPid(); | 93 return Process.myPid(); |
99 } | 94 } |
100 | 95 |
101 @Override | 96 @Override |
102 public void crashIntentionallyForTesting() { | 97 public void crashIntentionallyForTesting() { |
103 Process.killProcess(Process.myPid()); | 98 Process.killProcess(Process.myPid()); |
104 } | 99 } |
105 }; | 100 }; |
106 | 101 |
107 @Override | 102 // The ClassLoader for the host browser context. |
108 public void onCreate() { | 103 private ClassLoader mHostClassLoader; |
| 104 |
| 105 /* package */ static Context getContext() { |
| 106 return sContext.get(); |
| 107 } |
| 108 |
| 109 /** |
| 110 * Loads Chrome's native libraries and initializes a ChildProcessServiceImpl
. |
| 111 * @param context The application context. |
| 112 * @param hostBrowserContext The context of the host browser (i.e. Chrome). |
| 113 */ |
| 114 public void create(final Context context, final Context hostBrowserContext)
{ |
| 115 mHostClassLoader = hostBrowserContext.getClassLoader(); |
109 Log.i(TAG, "Creating new ChildProcessService pid=%d", Process.myPid()); | 116 Log.i(TAG, "Creating new ChildProcessService pid=%d", Process.myPid()); |
110 if (sContext.get() != null) { | 117 if (sContext.get() != null) { |
111 throw new RuntimeException("Illegal child process reuse."); | 118 throw new RuntimeException("Illegal child process reuse."); |
112 } | 119 } |
113 sContext.set(this); | 120 sContext.set(context); |
114 super.onCreate(); | |
115 | 121 |
116 ContextUtils.initApplicationContext(getApplicationContext()); | 122 // Initialize the context for the application that owns this ChildProces
sServiceImpl object. |
| 123 ContextUtils.initApplicationContext(context); |
117 | 124 |
118 mMainThread = new Thread(new Runnable() { | 125 mMainThread = new Thread(new Runnable() { |
119 @Override | 126 @Override |
120 @SuppressFBWarnings("DM_EXIT") | 127 @SuppressFBWarnings("DM_EXIT") |
121 public void run() { | 128 public void run() { |
122 try { | 129 try { |
123 // CommandLine must be initialized before everything else. | 130 // CommandLine must be initialized before everything else. |
124 synchronized (mMainThread) { | 131 synchronized (mMainThread) { |
125 while (mCommandLineParams == null) { | 132 while (mCommandLineParams == null) { |
126 mMainThread.wait(); | 133 mMainThread.wait(); |
(...skipping 18 matching lines...) Expand all Loading... |
145 } | 152 } |
146 } | 153 } |
147 boolean isLoaded = false; | 154 boolean isLoaded = false; |
148 if (CommandLine.getInstance().hasSwitch( | 155 if (CommandLine.getInstance().hasSwitch( |
149 BaseSwitches.RENDERER_WAIT_FOR_JAVA_DEBUGGER)) { | 156 BaseSwitches.RENDERER_WAIT_FOR_JAVA_DEBUGGER)) { |
150 android.os.Debug.waitForDebugger(); | 157 android.os.Debug.waitForDebugger(); |
151 } | 158 } |
152 | 159 |
153 boolean loadAtFixedAddressFailed = false; | 160 boolean loadAtFixedAddressFailed = false; |
154 try { | 161 try { |
155 LibraryLoader.get(mLibraryProcessType).loadNow(getApplic
ationContext()); | 162 LibraryLoader.get(mLibraryProcessType).loadNow(hostBrows
erContext); |
156 isLoaded = true; | 163 isLoaded = true; |
157 } catch (ProcessInitException e) { | 164 } catch (ProcessInitException e) { |
158 if (requestedSharedRelro) { | 165 if (requestedSharedRelro) { |
159 Log.w(TAG, "Failed to load native library with share
d RELRO, " | 166 Log.w(TAG, "Failed to load native library with share
d RELRO, " |
160 + "retrying without"); | 167 + "retrying without"); |
161 loadAtFixedAddressFailed = true; | 168 loadAtFixedAddressFailed = true; |
162 } else { | 169 } else { |
163 Log.e(TAG, "Failed to load native library", e); | 170 Log.e(TAG, "Failed to load native library", e); |
164 } | 171 } |
165 } | 172 } |
166 if (!isLoaded && requestedSharedRelro) { | 173 if (!isLoaded && requestedSharedRelro) { |
167 linker.disableSharedRelros(); | 174 linker.disableSharedRelros(); |
168 try { | 175 try { |
169 LibraryLoader.get(mLibraryProcessType).loadNow(getAp
plicationContext()); | 176 LibraryLoader.get(mLibraryProcessType).loadNow(hostB
rowserContext); |
170 isLoaded = true; | 177 isLoaded = true; |
171 } catch (ProcessInitException e) { | 178 } catch (ProcessInitException e) { |
172 Log.e(TAG, "Failed to load native library on retry",
e); | 179 Log.e(TAG, "Failed to load native library on retry",
e); |
173 } | 180 } |
174 } | 181 } |
175 if (!isLoaded) { | 182 if (!isLoaded) { |
176 System.exit(-1); | 183 System.exit(-1); |
177 } | 184 } |
178 LibraryLoader.get(mLibraryProcessType) | 185 LibraryLoader.get(mLibraryProcessType) |
179 .registerRendererProcessHistogram(requestedSharedRel
ro, | 186 .registerRendererProcessHistogram(requestedSharedRel
ro, |
180 loadAtFixedAddressFailed); | 187 loadAtFixedAddressFailed); |
181 LibraryLoader.get(mLibraryProcessType).initialize(); | 188 LibraryLoader.get(mLibraryProcessType).initialize(); |
182 synchronized (mMainThread) { | 189 synchronized (mMainThread) { |
183 mLibraryInitialized = true; | 190 mLibraryInitialized = true; |
184 mMainThread.notifyAll(); | 191 mMainThread.notifyAll(); |
185 while (mFdInfos == null) { | 192 while (mFdInfos == null) { |
186 mMainThread.wait(); | 193 mMainThread.wait(); |
187 } | 194 } |
188 } | 195 } |
189 for (FileDescriptorInfo fdInfo : mFdInfos) { | 196 for (FileDescriptorInfo fdInfo : mFdInfos) { |
190 nativeRegisterGlobalFileDescriptor( | 197 nativeRegisterGlobalFileDescriptor( |
191 fdInfo.mId, fdInfo.mFd.detachFd(), fdInfo.mOffse
t, fdInfo.mSize); | 198 fdInfo.mId, fdInfo.mFd.detachFd(), fdInfo.mOffse
t, fdInfo.mSize); |
192 } | 199 } |
193 nativeInitChildProcess(ChildProcessService.this, mCpuCount,
mCpuFeatures); | 200 nativeInitChildProcessImpl(ChildProcessServiceImpl.this, mCp
uCount, |
| 201 mCpuFeatures); |
194 if (mActivitySemaphore.tryAcquire()) { | 202 if (mActivitySemaphore.tryAcquire()) { |
195 ContentMain.start(); | 203 ContentMain.start(); |
196 nativeExitChildProcess(); | 204 nativeExitChildProcess(); |
197 } | 205 } |
198 } catch (InterruptedException e) { | 206 } catch (InterruptedException e) { |
199 Log.w(TAG, "%s startup failed: %s", MAIN_THREAD_NAME, e); | 207 Log.w(TAG, "%s startup failed: %s", MAIN_THREAD_NAME, e); |
200 } catch (ProcessInitException e) { | 208 } catch (ProcessInitException e) { |
201 Log.w(TAG, "%s startup failed: %s", MAIN_THREAD_NAME, e); | 209 Log.w(TAG, "%s startup failed: %s", MAIN_THREAD_NAME, e); |
202 } | 210 } |
203 } | 211 } |
204 }, MAIN_THREAD_NAME); | 212 }, MAIN_THREAD_NAME); |
205 mMainThread.start(); | 213 mMainThread.start(); |
206 } | 214 } |
207 | 215 |
208 @Override | |
209 @SuppressFBWarnings("DM_EXIT") | 216 @SuppressFBWarnings("DM_EXIT") |
210 public void onDestroy() { | 217 public void destroy() { |
211 Log.i(TAG, "Destroying ChildProcessService pid=%d", Process.myPid()); | 218 Log.i(TAG, "Destroying ChildProcessService pid=%d", Process.myPid()); |
212 super.onDestroy(); | |
213 if (mActivitySemaphore.tryAcquire()) { | 219 if (mActivitySemaphore.tryAcquire()) { |
214 // TODO(crbug.com/457406): This is a bit hacky, but there is no know
n better solution | 220 // 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). | 221 // 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 | 222 // In fact, we might really want to always exit() from onDestroy(),
not just from |
217 // the early return here. | 223 // the early return here. |
218 System.exit(0); | 224 System.exit(0); |
219 return; | 225 return; |
220 } | 226 } |
221 synchronized (mMainThread) { | 227 synchronized (mMainThread) { |
222 try { | 228 try { |
223 while (!mLibraryInitialized) { | 229 while (!mLibraryInitialized) { |
224 // Avoid a potential race in calling through to native code
before the library | 230 // Avoid a potential race in calling through to native code
before the library |
225 // has loaded. | 231 // has loaded. |
226 mMainThread.wait(); | 232 mMainThread.wait(); |
227 } | 233 } |
228 } catch (InterruptedException e) { | 234 } catch (InterruptedException e) { |
229 // Ignore | 235 // Ignore |
230 } | 236 } |
231 } | 237 } |
232 // Try to shutdown the MainThread gracefully, but it might not | 238 // Try to shutdown the MainThread gracefully, but it might not |
233 // have chance to exit normally. | 239 // have chance to exit normally. |
234 nativeShutdownMainThread(); | 240 nativeShutdownMainThread(); |
235 } | 241 } |
236 | 242 |
237 @Override | 243 public IBinder bind(Intent intent) { |
238 public IBinder onBind(Intent intent) { | |
239 // 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 | |
241 // child processes do not currently support reconnect; they must be init
ialized from | |
242 // scratch every time. | |
243 stopSelf(); | |
244 initializeParams(intent); | 244 initializeParams(intent); |
245 return mBinder; | 245 return mBinder; |
246 } | 246 } |
247 | 247 |
248 /** | 248 void initializeParams(Intent intent) { |
249 * Helper method to initialize the params from intent. | |
250 * @param intent Intent to launch the service. | |
251 */ | |
252 protected void initializeParams(Intent intent) { | |
253 synchronized (mMainThread) { | 249 synchronized (mMainThread) { |
254 mCommandLineParams = | 250 mCommandLineParams = |
255 intent.getStringArrayExtra(ChildProcessConstants.EXTRA_COMMA
ND_LINE); | 251 intent.getStringArrayExtra(ChildProcessConstants.EXTRA_COMMA
ND_LINE); |
256 // mLinkerParams is never used if Linker.isUsed() returns false. | 252 // mLinkerParams is never used if Linker.isUsed() returns false. |
257 // See onCreate(). | 253 // See onCreate(). |
258 mLinkerParams = new ChromiumLinkerParams(intent); | 254 mLinkerParams = new ChromiumLinkerParams(intent); |
259 mLibraryProcessType = ChildProcessCreationParams.getLibraryProcessTy
pe(intent); | 255 mLibraryProcessType = ChildProcessCreationParams.getLibraryProcessTy
pe(intent); |
260 mIsBound = true; | 256 mIsBound = true; |
261 mMainThread.notifyAll(); | 257 mMainThread.notifyAll(); |
262 } | 258 } |
263 } | 259 } |
264 | 260 |
265 /** | |
266 * 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. | |
268 */ | |
269 void getServiceInfo(Bundle bundle) { | 261 void getServiceInfo(Bundle bundle) { |
270 // Required to unparcel FileDescriptorInfo. | 262 // Required to unparcel FileDescriptorInfo. |
271 bundle.setClassLoader(getClassLoader()); | 263 bundle.setClassLoader(mHostClassLoader); |
272 synchronized (mMainThread) { | 264 synchronized (mMainThread) { |
273 // Allow the command line to be set via bind() intent or setupConnec
tion, but | 265 // Allow the command line to be set via bind() intent or setupConnec
tion, but |
274 // the FD can only be transferred here. | 266 // the FD can only be transferred here. |
275 if (mCommandLineParams == null) { | 267 if (mCommandLineParams == null) { |
276 mCommandLineParams = | 268 mCommandLineParams = |
277 bundle.getStringArray(ChildProcessConstants.EXTRA_COMMAN
D_LINE); | 269 bundle.getStringArray(ChildProcessConstants.EXTRA_COMMAN
D_LINE); |
278 } | 270 } |
279 // We must have received the command line by now | 271 // We must have received the command line by now |
280 assert mCommandLineParams != null; | 272 assert mCommandLineParams != null; |
281 mCpuCount = bundle.getInt(ChildProcessConstants.EXTRA_CPU_COUNT); | 273 mCpuCount = bundle.getInt(ChildProcessConstants.EXTRA_CPU_COUNT); |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 * This includes the IPC channel, the crash dump signals and resource relate
d | 408 * This includes the IPC channel, the crash dump signals and resource relate
d |
417 * files. | 409 * files. |
418 */ | 410 */ |
419 private static native void nativeRegisterGlobalFileDescriptor( | 411 private static native void nativeRegisterGlobalFileDescriptor( |
420 int id, int fd, long offset, long size); | 412 int id, int fd, long offset, long size); |
421 | 413 |
422 /** | 414 /** |
423 * The main entry point for a child process. This should be called from a ne
w thread since | 415 * 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} | 416 * it will not return until the child process exits. See child_process_servi
ce.{h,cc} |
425 * | 417 * |
426 * @param service The current ChildProcessService object. | 418 * @param serviceImpl The current ChildProcessServiceImpl object. |
427 * renderer. | 419 * renderer. |
428 */ | 420 */ |
429 private static native void nativeInitChildProcess( | 421 private static native void nativeInitChildProcessImpl( |
430 ChildProcessService service, int cpuCount, long cpuFeatures); | 422 ChildProcessServiceImpl serviceImpl, int cpuCount, long cpuFeatures)
; |
431 | 423 |
432 /** | 424 /** |
433 * Force the child process to exit. | 425 * Force the child process to exit. |
434 */ | 426 */ |
435 private static native void nativeExitChildProcess(); | 427 private static native void nativeExitChildProcess(); |
436 | 428 |
437 private native void nativeShutdownMainThread(); | 429 private native void nativeShutdownMainThread(); |
438 } | 430 } |
OLD | NEW |