OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 package org.chromium.content.app; | |
6 | |
7 import android.app.Service; | |
8 import android.content.Context; | |
9 import android.content.Intent; | |
10 import android.graphics.SurfaceTexture; | |
11 import android.os.Bundle; | |
12 import android.os.IBinder; | |
13 import android.os.ParcelFileDescriptor; | |
14 import android.os.Process; | |
15 import android.os.RemoteException; | |
16 import android.util.Log; | |
17 import android.view.Surface; | |
18 | |
19 import org.chromium.base.CalledByNative; | |
20 import org.chromium.content.app.ContentMain; | |
21 import org.chromium.content.browser.SandboxedProcessConnection; | |
22 import org.chromium.content.common.ISandboxedProcessCallback; | |
23 import org.chromium.content.common.ISandboxedProcessService; | |
24 import org.chromium.content.common.SurfaceCallback; | |
25 | |
26 /** | |
27 * This is the base class for sandboxed services; the SandboxedProcessService0, 1.. etc | |
28 * subclasses provide the concrete service entry points, to enable the browser t o connect | |
29 * to more than one distinct process (i.e. one process per service number, up to limit of N). | |
30 * The embedding application must declare these service instances in the applica tion section | |
31 * of its AndroidManifest.xml, for example with N entries of the form:- | |
32 * <service android:name="org.chromium.content.browser.SandboxedProcessServi ceX" | |
33 * android:process=":sandboxed_processX" /> | |
34 * for X in 0...N-1 (where N is {@link SandboxedProcessLauncher#MAX_REGISTERED_S ERVICES}) | |
35 */ | |
36 public class SandboxedProcessService extends Service { | |
37 private static final String MAIN_THREAD_NAME = "SandboxedProcessMain"; | |
38 private static final String TAG = "SandboxedProcessService"; | |
39 private ISandboxedProcessCallback mCallback; | |
40 | |
41 // This is the native "Main" thread for the renderer / utility process. | |
42 private Thread mSandboxMainThread; | |
43 // Parameters received via IPC, only accessed while holding the mSandboxMain Thread monitor. | |
44 private String[] mCommandLineParams; | |
45 private ParcelFileDescriptor mIPCFd; | |
46 private ParcelFileDescriptor mCrashFd; | |
47 private ParcelFileDescriptor mChromePakFd; | |
48 private ParcelFileDescriptor mLocalePakFd; | |
49 | |
50 private static Context sContext = null; | |
51 private boolean mLibraryInitialized = false; | |
52 | |
53 // Binder object used by clients for this service. | |
54 private final ISandboxedProcessService.Stub mBinder = new ISandboxedProcessS ervice.Stub() { | |
55 // NOTE: Implement any ISandboxedProcessService methods here. | |
56 @Override | |
57 public int setupConnection(Bundle args, ISandboxedProcessCallback callba ck) { | |
58 mCallback = callback; | |
59 synchronized (mSandboxMainThread) { | |
60 // Allow the command line to be set via bind() intent or setupCo nnection, but | |
61 // the FD can only be transferred here. | |
62 if (mCommandLineParams == null) { | |
63 mCommandLineParams = args.getStringArray( | |
64 SandboxedProcessConnection.EXTRA_COMMAND_LINE); | |
65 } | |
66 // We must have received the command line by now | |
67 assert mCommandLineParams != null; | |
68 mIPCFd = args.getParcelable(SandboxedProcessConnection.EXTRA_IPC _FD); | |
69 mLocalePakFd = args.getParcelable(SandboxedProcessConnection.EXT RA_LOCALE_PAK_FD); | |
70 // mCrashFd may be null if native crash reporting is disabled. | |
71 if (args.containsKey(SandboxedProcessConnection.EXTRA_CRASH_FD)) { | |
72 mCrashFd = args.getParcelable(SandboxedProcessConnection.EXT RA_CRASH_FD); | |
73 } | |
74 mSandboxMainThread.notifyAll(); | |
75 } | |
76 return Process.myPid(); | |
77 } | |
78 | |
79 @Override | |
80 public void setSurface(int type, Surface surface, int primaryID, int sec ondaryID) { | |
81 // This gives up ownership of the Surface. | |
82 SurfaceCallback.setSurface(type, surface, primaryID, secondaryID); | |
83 } | |
84 }; | |
85 | |
86 /* package */ static Context getContext() { | |
87 return sContext; | |
88 } | |
89 | |
90 @Override | |
91 public void onCreate() { | |
92 sContext = this; | |
93 super.onCreate(); | |
94 | |
95 mSandboxMainThread = new Thread(new Runnable() { | |
96 @Override | |
97 public void run() { | |
98 try { | |
99 // TODO(michaelbai): Upstream LibraryLoader.java | |
100 // if (!LibraryLoader.loadNow()) return; | |
101 synchronized (mSandboxMainThread) { | |
102 while (mCommandLineParams == null) { | |
103 mSandboxMainThread.wait(); | |
104 } | |
105 } | |
106 // LibraryLoader.initializeOnMainThread(mCommandLineParams); | |
107 synchronized (mSandboxMainThread) { | |
108 mLibraryInitialized = true; | |
109 mSandboxMainThread.notifyAll(); | |
110 while (mIPCFd == null) { | |
111 mSandboxMainThread.wait(); | |
112 } | |
113 } | |
114 int crashFd = (mCrashFd == null) ? -1 : mCrashFd.detachFd(); | |
115 ContentMain.initApplicationContext(sContext.getApplicationCo ntext()); | |
116 nativeInitSandboxedProcess(sContext.getApplicationContext(), | |
117 SandboxedProcessService.this, mIPCFd.detachFd(), cra shFd, | |
118 mChromePakFd.detachFd(), mLocalePakFd.detachFd()); | |
Yaron
2012/06/11 20:45:51
You're guaranteeing crashes here. Just pass NULL/0
michaelbai
2012/06/11 21:00:10
Removed them.
| |
119 ContentMain.start(); | |
120 nativeExitSandboxedProcess(); | |
121 } catch (InterruptedException e) { | |
122 Log.w(TAG, MAIN_THREAD_NAME + " startup failed: " + e); | |
123 } | |
124 } | |
125 }, MAIN_THREAD_NAME); | |
126 mSandboxMainThread.start(); | |
127 } | |
128 | |
129 @Override | |
130 public void onDestroy() { | |
131 super.onDestroy(); | |
132 if (mCommandLineParams == null) { | |
133 // This process was destroyed before it even started. Nothing more t o do. | |
134 return; | |
135 } | |
136 synchronized (mSandboxMainThread) { | |
137 try { | |
138 while (!mLibraryInitialized) { | |
139 // Avoid a potential race in calling through to native code before the library | |
140 // has loaded. | |
141 mSandboxMainThread.wait(); | |
142 } | |
143 } catch (InterruptedException e) { | |
144 } | |
145 } | |
146 | |
147 // This is not synchronized with the main thread in any way, but this is analogous | |
148 // to how desktop chrome terminates processes using SIGTERM. The mSandbo xMainThread | |
149 // may run briefly before this is executed, but will eventually get a ch annel error | |
150 // and similarly commit suicide via SuicideOnChannelErrorFilter(). | |
151 // TODO(tedbo): Why doesn't the activity manager SIGTERM/SIGKILL this se rvice process? | |
152 nativeExitSandboxedProcess(); | |
153 } | |
154 | |
155 @Override | |
156 public IBinder onBind(Intent intent) { | |
157 // We call stopSelf() to request that this service be stopped as soon as the client | |
158 // unbinds. Otherwise the system may keep it around and available for a reconnect. The | |
159 // sandboxed processes do not currently support reconnect; they must be initialized from | |
160 // scratch every time. | |
161 stopSelf(); | |
162 | |
163 synchronized (mSandboxMainThread) { | |
164 mCommandLineParams = intent.getStringArrayExtra( | |
165 SandboxedProcessConnection.EXTRA_COMMAND_LINE); | |
166 mSandboxMainThread.notifyAll(); | |
167 } | |
168 | |
169 return mBinder; | |
170 } | |
171 | |
172 /** | |
173 * Called from native code to share a surface texture with another child pro cess. | |
174 * Through using the callback object the browser is used as a proxy to route the | |
175 * call to the correct process. | |
176 * | |
177 * @param pid Process handle of the sandboxed process to share the SurfaceTe xture with. | |
178 * @param type The type of process that the SurfaceTexture is for. | |
179 * @param surfaceObject The Surface or SurfaceTexture to share with the othe r sandboxed process. | |
180 * @param primaryID Used to route the call to the correct client instance. | |
181 * @param secondaryID Used to route the call to the correct client instance. | |
182 */ | |
183 @SuppressWarnings("unused") | |
184 @CalledByNative | |
185 private void establishSurfaceTexturePeer(int pid, int type, Object surfaceOb ject, int primaryID, | |
186 int secondaryID) { | |
187 if (mCallback == null) { | |
188 Log.e(TAG, "No callback interface has been provided."); | |
189 return; | |
190 } | |
191 | |
192 Surface surface = null; | |
193 boolean needRelease = false; | |
194 if (surfaceObject instanceof Surface) { | |
195 surface = (Surface)surfaceObject; | |
196 } else if (surfaceObject instanceof SurfaceTexture) { | |
197 surface = new Surface((SurfaceTexture)surfaceObject); | |
198 needRelease = true; | |
199 } else { | |
200 Log.e(TAG, "Not a valid surfaceObject: " + surfaceObject); | |
201 return; | |
202 } | |
203 try { | |
204 mCallback.establishSurfacePeer(pid, type, surface, primaryID, second aryID); | |
205 } catch (RemoteException e) { | |
206 Log.e(TAG, "Unable to call establishSurfaceTexturePeer: " + e); | |
207 return; | |
208 } finally { | |
209 if (needRelease) { | |
210 surface.release(); | |
211 } | |
212 } | |
213 } | |
214 | |
215 /** | |
216 * The main entry point for a sandboxed process. This should be called from a new thread since | |
217 * it will not return until the sandboxed process exits. See sandboxed_proce ss_service.{h,cc} | |
218 * | |
219 * @param applicationContext The Application Context of the current process. | |
220 * @param service The current SandboxedProcessService object. | |
221 * @param ipcFd File descriptor to use for ipc. | |
222 * @param crashFd File descriptor for signaling crashes. | |
223 */ | |
224 private static native void nativeInitSandboxedProcess(Context applicationCon text, | |
225 SandboxedProcessService service, int ipcFd, int crashFd, int chromeP akFd, | |
226 int localePakFd); | |
227 | |
228 /** | |
229 * Force the sandboxed process to exit. | |
230 */ | |
231 private static native void nativeExitSandboxedProcess(); | |
232 } | |
OLD | NEW |