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

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/SandboxedProcessLauncher.java

Issue 12321131: Renamed Sandboxed process to Child process (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: updated findbugs_known_bugs.txt Created 7 years, 9 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
(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.browser;
6
7 import android.content.Context;
8 import android.os.RemoteException;
9 import android.util.Log;
10 import android.view.Surface;
11
12 import java.util.Arrays;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.concurrent.ConcurrentHashMap;
17
18 import org.chromium.base.CalledByNative;
19 import org.chromium.base.JNINamespace;
20 import org.chromium.base.ThreadUtils;
21 import org.chromium.content.app.LibraryLoader;
22 import org.chromium.content.common.ISandboxedProcessCallback;
23 import org.chromium.content.common.ISandboxedProcessService;
24
25 /**
26 * This class provides the method to start/stop SandboxedProcess called by
27 * native.
28 */
29 @JNINamespace("content")
30 public class SandboxedProcessLauncher {
31 private static String TAG = "SandboxedProcessLauncher";
32
33 private static final int CALLBACK_FOR_UNKNOWN_PROCESS = 0;
34 private static final int CALLBACK_FOR_GPU_PROCESS = 1;
35 private static final int CALLBACK_FOR_RENDERER_PROCESS = 2;
36
37 // The upper limit on the number of simultaneous service process instances s upported.
38 // This must not exceed total number of SandboxedProcessServiceX classes dec lared in
39 // this package, and defined as services in the embedding application's mani fest file.
40 // (See {@link SandboxedProcessService} for more details on defining the ser vices.)
41 /* package */ static final int MAX_REGISTERED_SERVICES = 6;
42 private static final SandboxedProcessConnection[] mConnections =
43 new SandboxedProcessConnection[MAX_REGISTERED_SERVICES];
44 // The list of free slots in mConnections. When looking for a free connecti on,
45 // the first index in that list should be used. When a connection is freed, its index
46 // is added to the end of the list. This is so that we avoid immediately reu sing a freed
47 // connection (see bug crbug.com/164069): the framework might keep a service process alive
48 // when it's been unbound for a short time. If a connection to that same se rvice is bound
49 // at that point, the process is reused and bad things happen (mostly static variables are
50 // set when we don't expect them to).
51 // SHOULD BE ACCESSED WITH THE mConnections LOCK.
52 private static final ArrayList<Integer> mFreeConnectionIndices =
53 new ArrayList<Integer>(MAX_REGISTERED_SERVICES);
54 static {
55 for (int i = 0; i < MAX_REGISTERED_SERVICES; i++) {
56 mFreeConnectionIndices.add(i);
57 }
58 }
59
60 private static SandboxedProcessConnection allocateConnection(Context context ) {
61 SandboxedProcessConnection.DeathCallback deathCallback =
62 new SandboxedProcessConnection.DeathCallback() {
63 @Override
64 public void onSandboxedProcessDied(int pid) {
65 stop(pid);
66 }
67 };
68 synchronized (mConnections) {
69 if (mFreeConnectionIndices.isEmpty()) {
70 Log.w(TAG, "Ran out of sandboxed services.");
71 return null;
72 }
73 int slot = mFreeConnectionIndices.remove(0);
74 assert mConnections[slot] == null;
75 mConnections[slot] = new SandboxedProcessConnection(context, slot, d eathCallback);
76 return mConnections[slot];
77 }
78 }
79
80 private static SandboxedProcessConnection allocateBoundConnection(Context co ntext,
81 String[] commandLine) {
82 SandboxedProcessConnection connection = allocateConnection(context);
83 if (connection != null) {
84 String libraryName = LibraryLoader.getLibraryToLoad();
85 assert libraryName != null : "Attempting to launch a sandbox process without first "
86 + "calling LibraryLoader.setLibraryToLoad";
87 connection.bind(libraryName, commandLine);
88 }
89 return connection;
90 }
91
92 private static void freeConnection(SandboxedProcessConnection connection) {
93 if (connection == null) {
94 return;
95 }
96 int slot = connection.getServiceNumber();
97 synchronized (mConnections) {
98 if (mConnections[slot] != connection) {
99 int occupier = mConnections[slot] == null ?
100 -1 : mConnections[slot].getServiceNumber();
101 Log.e(TAG, "Unable to find connection to free in slot: " + slot +
102 " already occupied by service: " + occupier);
103 assert false;
104 } else {
105 mConnections[slot] = null;
106 assert !mFreeConnectionIndices.contains(slot);
107 mFreeConnectionIndices.add(slot);
108 }
109 }
110 }
111
112 public static int getNumberOfConnections() {
113 synchronized (mConnections) {
114 return mFreeConnectionIndices.size();
115 }
116 }
117
118 // Represents an invalid process handle; same as base/process.h kNullProcess Handle.
119 private static final int NULL_PROCESS_HANDLE = 0;
120
121 // Map from pid to SandboxedService connection.
122 private static Map<Integer, SandboxedProcessConnection> mServiceMap =
123 new ConcurrentHashMap<Integer, SandboxedProcessConnection>();
124
125 // A pre-allocated and pre-bound connection ready for connection setup, or n ull.
126 static SandboxedProcessConnection mSpareConnection = null;
127
128 /**
129 * Returns the sandboxed process service interface for the given pid. This m ay be called on
130 * any thread, but the caller must assume that the service can disconnect at any time. All
131 * service calls should catch and handle android.os.RemoteException.
132 *
133 * @param pid The pid (process handle) of the service obtained from {@link # start}.
134 * @return The ISandboxedProcessService or null if the service no longer exi sts.
135 */
136 public static ISandboxedProcessService getSandboxedService(int pid) {
137 SandboxedProcessConnection connection = mServiceMap.get(pid);
138 if (connection != null) {
139 return connection.getService();
140 }
141 return null;
142 }
143
144 /**
145 * Should be called early in startup so the work needed to spawn the sandbox ed process can
146 * be done in parallel to other startup work. Must not be called on the UI t hread.
147 * @param context the application context used for the connection.
148 */
149 public static synchronized void warmUp(Context context) {
150 assert !ThreadUtils.runningOnUiThread();
151 if (mSpareConnection == null) {
152 mSpareConnection = allocateBoundConnection(context, null);
153 }
154 }
155
156 /**
157 * Spawns and connects to a sandboxed process. May be called on any thread. It will not
158 * block, but will instead callback to {@link #nativeOnSandboxedProcessStart ed} when the
159 * connection is established. Note this callback will not necessarily be fro m the same thread
160 * (currently it always comes from the main thread).
161 *
162 * @param context Context used to obtain the application context.
163 * @param commandLine The sandboxed process command line argv.
164 * @param file_ids The ID that should be used when mapping files in the crea ted process.
165 * @param file_fds The file descriptors that should be mapped in the created process.
166 * @param file_auto_close Whether the file descriptors should be closed once they were passed to
167 * the created process.
168 * @param clientContext Arbitrary parameter used by the client to distinguis h this connection.
169 */
170 @CalledByNative
171 static void start(
172 Context context,
173 final String[] commandLine,
174 int[] fileIds,
175 int[] fileFds,
176 boolean[] fileAutoClose,
177 final int clientContext) {
178 assert fileIds.length == fileFds.length && fileFds.length == fileAutoClo se.length;
179 FileDescriptorInfo[] filesToBeMapped = new FileDescriptorInfo[fileFds.le ngth];
180 for (int i = 0; i < fileFds.length; i++) {
181 filesToBeMapped[i] =
182 new FileDescriptorInfo(fileIds[i], fileFds[i], fileAutoClose [i]);
183 }
184 assert clientContext != 0;
185 SandboxedProcessConnection allocatedConnection;
186 synchronized (SandboxedProcessLauncher.class) {
187 allocatedConnection = mSpareConnection;
188 mSpareConnection = null;
189 }
190 if (allocatedConnection == null) {
191 allocatedConnection = allocateBoundConnection(context, commandLine);
192 if (allocatedConnection == null) {
193 // Notify the native code so it can free the heap allocated call back.
194 nativeOnSandboxedProcessStarted(clientContext, 0);
195 return;
196 }
197 }
198 final SandboxedProcessConnection connection = allocatedConnection;
199 Log.d(TAG, "Setting up connection to process: slot=" + connection.getSer viceNumber());
200 // Note: This runnable will be executed when the sandboxed connection is setup.
201 final Runnable onConnect = new Runnable() {
202 @Override
203 public void run() {
204 final int pid = connection.getPid();
205 Log.d(TAG, "on connect callback, pid=" + pid + " context=" + cli entContext);
206 if (pid != NULL_PROCESS_HANDLE) {
207 mServiceMap.put(pid, connection);
208 } else {
209 freeConnection(connection);
210 }
211 nativeOnSandboxedProcessStarted(clientContext, pid);
212 }
213 };
214 int callbackType = CALLBACK_FOR_UNKNOWN_PROCESS;
215 List<String> commandLineList = Arrays.asList(commandLine);
216 if (commandLineList.contains("--type=renderer")) {
217 callbackType = CALLBACK_FOR_RENDERER_PROCESS;
218 } else if (commandLineList.contains("--type=gpu-process")) {
219 callbackType = CALLBACK_FOR_GPU_PROCESS;
220 }
221 // TODO(sievers): Revisit this as it doesn't correctly handle the utilit y process
222 // assert callbackType != CALLBACK_FOR_UNKNOWN_PROCESS;
223
224 connection.setupConnection(
225 commandLine, filesToBeMapped, createCallback(callbackType), onCo nnect);
226 }
227
228 /**
229 * Terminates a sandboxed process. This may be called from any thread.
230 *
231 * @param pid The pid (process handle) of the service connection obtained fr om {@link #start}.
232 */
233 @CalledByNative
234 static void stop(int pid) {
235 Log.d(TAG, "stopping sandboxed connection: pid=" + pid);
236
237 SandboxedProcessConnection connection = mServiceMap.remove(pid);
238 if (connection == null) {
239 Log.w(TAG, "Tried to stop non-existent connection to pid: " + pid);
240 return;
241 }
242 connection.unbind();
243 freeConnection(connection);
244 }
245
246 /**
247 * Bind a sandboxed process as a high priority process so that it has the sa me
248 * priority as the main process. This can be used for the foreground rendere r
249 * process to distinguish it from the the background renderer process.
250 *
251 * @param pid The process handle of the service connection obtained from {@l ink #start}.
252 */
253 static void bindAsHighPriority(int pid) {
254 SandboxedProcessConnection connection = mServiceMap.get(pid);
255 if (connection == null) {
256 Log.w(TAG, "Tried to bind a non-existent connection to pid: " + pid) ;
257 return;
258 }
259 connection.bindHighPriority();
260 }
261
262 /**
263 * Unbind a high priority process which is bound by {@link #bindAsHighPriori ty}.
264 *
265 * @param pid The process handle of the service obtained from {@link #start} .
266 */
267 static void unbindAsHighPriority(int pid) {
268 SandboxedProcessConnection connection = mServiceMap.get(pid);
269 if (connection == null) {
270 Log.w(TAG, "Tried to unbind non-existent connection to pid: " + pid) ;
271 return;
272 }
273 connection.unbindHighPriority(false);
274 }
275
276 /**
277 * This implementation is used to receive callbacks from the remote service.
278 */
279 private static ISandboxedProcessCallback createCallback(final int callbackTy pe) {
280 return new ISandboxedProcessCallback.Stub() {
281 /**
282 * This is called by the remote service regularly to tell us about
283 * new values. Note that IPC calls are dispatched through a thread
284 * pool running in each process, so the code executing here will
285 * NOT be running in our main thread -- so, to update the UI, we nee d
286 * to use a Handler.
287 */
288 @Override
289 public void establishSurfacePeer(
290 int pid, Surface surface, int primaryID, int secondaryID) {
291 // Do not allow a malicious renderer to connect to a producer. T his is only
292 // used from stream textures managed by the GPU process.
293 if (callbackType != CALLBACK_FOR_GPU_PROCESS) {
294 Log.e(TAG, "Illegal callback for non-GPU process.");
295 return;
296 }
297
298 nativeEstablishSurfacePeer(pid, surface, primaryID, secondaryID) ;
299 }
300
301 @Override
302 public Surface getViewSurface(int surfaceId) {
303 // Do not allow a malicious renderer to get to our view surface.
304 if (callbackType != CALLBACK_FOR_GPU_PROCESS) {
305 Log.e(TAG, "Illegal callback for non-GPU process.");
306 return null;
307 }
308
309 return nativeGetViewSurface(surfaceId);
310 }
311 };
312 };
313
314 private static native void nativeOnSandboxedProcessStarted(int clientContext , int pid);
315 private static native Surface nativeGetViewSurface(int surfaceId);
316 private static native void nativeEstablishSurfacePeer(
317 int pid, Surface surface, int primaryID, int secondaryID);
318 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698