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

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

Powered by Google App Engine
This is Rietveld 408576698