blob: 157c0bf0ec137166d6aaf877c2707d9a82415e2e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.os;
18
19import android.content.pm.ActivityInfo;
20import android.content.res.Resources;
21import android.content.res.TypedArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.graphics.drawable.Drawable;
23import android.net.LocalServerSocket;
24import android.os.Debug;
Mike Lockwood90960e82010-08-06 09:15:25 -040025import android.os.FileUtils;
Jeff Brownebed7d62011-05-16 17:08:42 -070026import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.os.SystemClock;
28import android.os.SystemProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.util.EventLog;
30import android.util.Log;
31
32import dalvik.system.VMRuntime;
33import dalvik.system.Zygote;
34
Brian Carlstrom46703b02011-04-06 15:41:29 -070035import libcore.io.IoUtils;
36
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import java.io.BufferedReader;
38import java.io.FileDescriptor;
39import java.io.IOException;
40import java.io.InputStream;
41import java.io.InputStreamReader;
42import java.lang.reflect.InvocationTargetException;
43import java.lang.reflect.Method;
44import java.lang.reflect.Modifier;
45import java.util.ArrayList;
46
47/**
48 * Startup class for the zygote process.
49 *
50 * Pre-initializes some classes, and then waits for commands on a UNIX domain
51 * socket. Based on these commands, forks of child processes that inherit
52 * the initial state of the VM.
53 *
54 * Please see {@link ZygoteConnection.Arguments} for documentation on the
55 * client protocol.
56 *
57 * @hide
58 */
59public class ZygoteInit {
60
61 private static final String TAG = "Zygote";
62
63 private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";
64
65 private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
66 private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
67
68 /** when preloading, GC after allocating this many bytes */
69 private static final int PRELOAD_GC_THRESHOLD = 50000;
70
Barry Hayes0b3533a2010-01-20 12:46:47 -080071 public static final String USAGE_STRING =
Jeff Brownebed7d62011-05-16 17:08:42 -070072 " <\"start-system-server\"|\"\" for startSystemServer>";
Barry Hayes0b3533a2010-01-20 12:46:47 -080073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 private static LocalServerSocket sServerSocket;
75
76 /**
77 * Used to pre-load resources. We hold a global reference on it so it
78 * never gets destroyed.
79 */
80 private static Resources mResources;
Bob Leee5408332009-09-04 18:31:17 -070081
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 /**
83 * The number of times that the main Zygote loop
84 * should run before calling gc() again.
85 */
86 static final int GC_LOOP_COUNT = 10;
87
88 /**
89 * If true, zygote forks for each peer. If false, a select loop is used
90 * inside a single process. The latter is preferred.
91 */
92 private static final boolean ZYGOTE_FORK_MODE = false;
93
94 /**
95 * The name of a resource file that contains classes to preload.
96 */
97 private static final String PRELOADED_CLASSES = "preloaded-classes";
98
99 /** Controls whether we should preload resources during zygote init. */
100 private static final boolean PRELOAD_RESOURCES = true;
Andy McFadden599c9182009-04-08 00:35:56 -0700101
102 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 * Invokes a static "main(argv[]) method on class "className".
104 * Converts various failing exceptions into RuntimeExceptions, with
105 * the assumption that they will then cause the VM instance to exit.
106 *
107 * @param loader class loader to use
108 * @param className Fully-qualified class name
109 * @param argv Argument vector for main()
110 */
111 static void invokeStaticMain(ClassLoader loader,
112 String className, String[] argv)
113 throws ZygoteInit.MethodAndArgsCaller {
114 Class<?> cl;
115
116 try {
117 cl = loader.loadClass(className);
118 } catch (ClassNotFoundException ex) {
119 throw new RuntimeException(
120 "Missing class when invoking static main " + className,
121 ex);
122 }
123
124 Method m;
125 try {
126 m = cl.getMethod("main", new Class[] { String[].class });
127 } catch (NoSuchMethodException ex) {
128 throw new RuntimeException(
129 "Missing static main on " + className, ex);
130 } catch (SecurityException ex) {
131 throw new RuntimeException(
132 "Problem getting static main on " + className, ex);
133 }
134
135 int modifiers = m.getModifiers();
136 if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
137 throw new RuntimeException(
138 "Main method is not public and static on " + className);
139 }
140
141 /*
142 * This throw gets caught in ZygoteInit.main(), which responds
143 * by invoking the exception's run() method. This arrangement
144 * clears up all the stack frames that were required in setting
145 * up the process.
146 */
147 throw new ZygoteInit.MethodAndArgsCaller(m, argv);
148 }
149
150 /**
151 * Registers a server socket for zygote command connections
152 *
153 * @throws RuntimeException when open fails
154 */
155 private static void registerZygoteSocket() {
156 if (sServerSocket == null) {
157 int fileDesc;
158 try {
159 String env = System.getenv(ANDROID_SOCKET_ENV);
160 fileDesc = Integer.parseInt(env);
161 } catch (RuntimeException ex) {
162 throw new RuntimeException(
163 ANDROID_SOCKET_ENV + " unset or invalid", ex);
164 }
165
166 try {
167 sServerSocket = new LocalServerSocket(
168 createFileDescriptor(fileDesc));
169 } catch (IOException ex) {
170 throw new RuntimeException(
171 "Error binding to local socket '" + fileDesc + "'", ex);
172 }
173 }
174 }
175
176 /**
177 * Waits for and accepts a single command connection. Throws
178 * RuntimeException on failure.
179 */
180 private static ZygoteConnection acceptCommandPeer() {
Bob Leee5408332009-09-04 18:31:17 -0700181 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 return new ZygoteConnection(sServerSocket.accept());
183 } catch (IOException ex) {
184 throw new RuntimeException(
185 "IOException during accept()", ex);
186 }
187 }
188
189 /**
190 * Close and clean up zygote sockets. Called on shutdown and on the
191 * child's exit path.
192 */
193 static void closeServerSocket() {
194 try {
195 if (sServerSocket != null) {
196 sServerSocket.close();
197 }
198 } catch (IOException ex) {
199 Log.e(TAG, "Zygote: error closing sockets", ex);
200 }
201
202 sServerSocket = null;
203 }
204
205 private static final int UNPRIVILEGED_UID = 9999;
206 private static final int UNPRIVILEGED_GID = 9999;
207
208 private static final int ROOT_UID = 0;
209 private static final int ROOT_GID = 0;
210
211 /**
212 * Sets effective user ID.
213 */
214 private static void setEffectiveUser(int uid) {
215 int errno = setreuid(ROOT_UID, uid);
216 if (errno != 0) {
217 Log.e(TAG, "setreuid() failed. errno: " + errno);
218 }
219 }
220
221 /**
222 * Sets effective group ID.
223 */
224 private static void setEffectiveGroup(int gid) {
225 int errno = setregid(ROOT_GID, gid);
226 if (errno != 0) {
227 Log.e(TAG, "setregid() failed. errno: " + errno);
228 }
229 }
230
231 /**
232 * Performs Zygote process initialization. Loads and initializes
233 * commonly used classes.
234 *
235 * Most classes only cause a few hundred bytes to be allocated, but
236 * a few will allocate a dozen Kbytes (in one case, 500+K).
237 */
238 private static void preloadClasses() {
239 final VMRuntime runtime = VMRuntime.getRuntime();
Bob Leee5408332009-09-04 18:31:17 -0700240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 InputStream is = ZygoteInit.class.getClassLoader().getResourceAsStream(
242 PRELOADED_CLASSES);
243 if (is == null) {
244 Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
245 } else {
246 Log.i(TAG, "Preloading classes...");
247 long startTime = SystemClock.uptimeMillis();
Bob Leee5408332009-09-04 18:31:17 -0700248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 // Drop root perms while running static initializers.
250 setEffectiveGroup(UNPRIVILEGED_GID);
251 setEffectiveUser(UNPRIVILEGED_UID);
252
253 // Alter the target heap utilization. With explicit GCs this
254 // is not likely to have any effect.
255 float defaultUtilization = runtime.getTargetHeapUtilization();
256 runtime.setTargetHeapUtilization(0.8f);
257
258 // Start with a clean slate.
Brian Carlstrom08065b92011-04-01 15:49:41 -0700259 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 runtime.runFinalizationSync();
261 Debug.startAllocCounting();
262
263 try {
Bob Leee5408332009-09-04 18:31:17 -0700264 BufferedReader br
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 = new BufferedReader(new InputStreamReader(is), 256);
266
267 int count = 0;
268 String line;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269 while ((line = br.readLine()) != null) {
270 // Skip comments and blank lines.
271 line = line.trim();
272 if (line.startsWith("#") || line.equals("")) {
273 continue;
274 }
275
276 try {
Joe Onorato43a17652011-04-06 19:22:23 -0700277 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278 Log.v(TAG, "Preloading " + line + "...");
279 }
280 Class.forName(line);
281 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700282 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 Log.v(TAG,
284 " GC at " + Debug.getGlobalAllocSize());
285 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700286 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287 runtime.runFinalizationSync();
288 Debug.resetGlobalAllocSize();
289 }
290 count++;
291 } catch (ClassNotFoundException e) {
Jesse Wilsone2417542010-06-03 12:33:26 -0700292 Log.w(TAG, "Class not found for preloading: " + line);
Bob Lee2e93f652009-08-11 01:16:03 -0700293 } catch (Throwable t) {
294 Log.e(TAG, "Error preloading " + line + ".", t);
295 if (t instanceof Error) {
296 throw (Error) t;
297 }
298 if (t instanceof RuntimeException) {
299 throw (RuntimeException) t;
300 }
301 throw new RuntimeException(t);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 }
303 }
304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 Log.i(TAG, "...preloaded " + count + " classes in "
306 + (SystemClock.uptimeMillis()-startTime) + "ms.");
307 } catch (IOException e) {
308 Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
309 } finally {
Brian Carlstrom46703b02011-04-06 15:41:29 -0700310 IoUtils.closeQuietly(is);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 // Restore default.
312 runtime.setTargetHeapUtilization(defaultUtilization);
313
314 Debug.stopAllocCounting();
315
316 // Bring back root. We'll need it later.
317 setEffectiveUser(ROOT_UID);
318 setEffectiveGroup(ROOT_GID);
319 }
320 }
321 }
322
323 /**
324 * Load in commonly used resources, so they can be shared across
325 * processes.
326 *
327 * These tend to be a few Kbytes, but are frequently in the 20-40K
328 * range, and occasionally even larger.
329 */
330 private static void preloadResources() {
331 final VMRuntime runtime = VMRuntime.getRuntime();
Bob Leee5408332009-09-04 18:31:17 -0700332
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800333 Debug.startAllocCounting();
334 try {
Brian Carlstrom08065b92011-04-01 15:49:41 -0700335 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 runtime.runFinalizationSync();
337 mResources = Resources.getSystem();
338 mResources.startPreloading();
339 if (PRELOAD_RESOURCES) {
340 Log.i(TAG, "Preloading resources...");
341
342 long startTime = SystemClock.uptimeMillis();
343 TypedArray ar = mResources.obtainTypedArray(
344 com.android.internal.R.array.preloaded_drawables);
345 int N = preloadDrawables(runtime, ar);
346 Log.i(TAG, "...preloaded " + N + " resources in "
347 + (SystemClock.uptimeMillis()-startTime) + "ms.");
348
349 startTime = SystemClock.uptimeMillis();
350 ar = mResources.obtainTypedArray(
351 com.android.internal.R.array.preloaded_color_state_lists);
352 N = preloadColorStateLists(runtime, ar);
353 Log.i(TAG, "...preloaded " + N + " resources in "
354 + (SystemClock.uptimeMillis()-startTime) + "ms.");
355 }
356 mResources.finishPreloading();
357 } catch (RuntimeException e) {
358 Log.w(TAG, "Failure preloading resources", e);
359 } finally {
360 Debug.stopAllocCounting();
361 }
362 }
363
364 private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) {
365 int N = ar.length();
366 for (int i=0; i<N; i++) {
367 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700368 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
370 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700371 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 runtime.runFinalizationSync();
373 Debug.resetGlobalAllocSize();
374 }
375 int id = ar.getResourceId(i, 0);
Joe Onorato43a17652011-04-06 19:22:23 -0700376 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
378 }
379 if (id != 0) {
380 mResources.getColorStateList(id);
381 }
382 }
383 return N;
384 }
385
386
387 private static int preloadDrawables(VMRuntime runtime, TypedArray ar) {
388 int N = ar.length();
389 for (int i=0; i<N; i++) {
390 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700391 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
393 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700394 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 runtime.runFinalizationSync();
396 Debug.resetGlobalAllocSize();
397 }
398 int id = ar.getResourceId(i, 0);
Joe Onorato43a17652011-04-06 19:22:23 -0700399 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
401 }
402 if (id != 0) {
403 Drawable dr = mResources.getDrawable(id);
404 if ((dr.getChangingConfigurations()&~ActivityInfo.CONFIG_FONT_SCALE) != 0) {
405 Log.w(TAG, "Preloaded drawable resource #0x"
406 + Integer.toHexString(id)
407 + " (" + ar.getString(i) + ") that varies with configuration!!");
408 }
409 }
410 }
411 return N;
412 }
413
414 /**
415 * Runs several special GCs to try to clean up a few generations of
416 * softly- and final-reachable objects, along with any other garbage.
417 * This is only useful just before a fork().
418 */
419 /*package*/ static void gc() {
420 final VMRuntime runtime = VMRuntime.getRuntime();
421
422 /* runFinalizationSync() lets finalizers be called in Zygote,
423 * which doesn't have a HeapWorker thread.
424 */
Brian Carlstrom08065b92011-04-01 15:49:41 -0700425 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 runtime.runFinalizationSync();
Brian Carlstrom08065b92011-04-01 15:49:41 -0700427 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 runtime.runFinalizationSync();
Brian Carlstrom08065b92011-04-01 15:49:41 -0700429 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 runtime.runFinalizationSync();
431 }
432
433 /**
434 * Finish remaining work for the newly forked system server process.
435 */
436 private static void handleSystemServerProcess(
437 ZygoteConnection.Arguments parsedArgs)
438 throws ZygoteInit.MethodAndArgsCaller {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439
440 closeServerSocket();
441
Mike Lockwood90960e82010-08-06 09:15:25 -0400442 // set umask to 0077 so new files and directories will default to owner-only permissions.
443 FileUtils.setUMask(FileUtils.S_IRWXG | FileUtils.S_IRWXO);
444
Jeff Brownebed7d62011-05-16 17:08:42 -0700445 if (parsedArgs.niceName != null) {
446 Process.setArgV0(parsedArgs.niceName);
447 }
448
449 if (parsedArgs.invokeWith != null) {
450 WrapperInit.execApplication(parsedArgs.invokeWith,
451 parsedArgs.niceName, null, parsedArgs.remainingArgs);
452 } else {
453 /*
454 * Pass the remaining arguments to SystemServer.
455 */
456 RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
457 }
458
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 /* should never reach here */
460 }
461
462 /**
463 * Prepare the arguments and fork for the system server process.
464 */
Bob Leee5408332009-09-04 18:31:17 -0700465 private static boolean startSystemServer()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 throws MethodAndArgsCaller, RuntimeException {
467 /* Hardcoded command line to start the system server */
468 String args[] = {
469 "--setuid=1000",
470 "--setgid=1000",
Mike Lockwood037a0862010-07-27 18:42:44 -0400471 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003",
San Mehat1caefa62009-06-10 09:09:51 -0700472 "--capabilities=130104352,130104352",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 "--runtime-init",
474 "--nice-name=system_server",
475 "com.android.server.SystemServer",
476 };
477 ZygoteConnection.Arguments parsedArgs = null;
478
479 int pid;
480
481 try {
482 parsedArgs = new ZygoteConnection.Arguments(args);
Jeff Brownebed7d62011-05-16 17:08:42 -0700483 ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
484 ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485
486 /* Request to fork the system server process */
487 pid = Zygote.forkSystemServer(
488 parsedArgs.uid, parsedArgs.gid,
Jeff Brownebed7d62011-05-16 17:08:42 -0700489 parsedArgs.gids, parsedArgs.debugFlags, null,
Andy McFadden1b4c7962010-10-27 11:26:05 -0700490 parsedArgs.permittedCapabilities,
491 parsedArgs.effectiveCapabilities);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 } catch (IllegalArgumentException ex) {
493 throw new RuntimeException(ex);
Bob Leee5408332009-09-04 18:31:17 -0700494 }
495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 /* For child process */
497 if (pid == 0) {
498 handleSystemServerProcess(parsedArgs);
499 }
500
501 return true;
502 }
503
504 public static void main(String argv[]) {
505 try {
Bob Leee5408332009-09-04 18:31:17 -0700506 // Start profiling the zygote initialization.
507 SamplingProfilerIntegration.start();
508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 registerZygoteSocket();
510 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
511 SystemClock.uptimeMillis());
512 preloadClasses();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 preloadResources();
514 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
515 SystemClock.uptimeMillis());
516
Brian Carlstrom17510862010-08-18 14:27:40 -0700517 // Finish profiling the zygote initialization.
518 SamplingProfilerIntegration.writeZygoteSnapshot();
Bob Leee5408332009-09-04 18:31:17 -0700519
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 // Do an initial gc to clean up after startup
521 gc();
522
523 // If requested, start system server directly from Zygote
524 if (argv.length != 2) {
Barry Hayes0b3533a2010-01-20 12:46:47 -0800525 throw new RuntimeException(argv[0] + USAGE_STRING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 }
527
Jeff Brownebed7d62011-05-16 17:08:42 -0700528 if (argv[1].equals("start-system-server")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 startSystemServer();
Jeff Brownebed7d62011-05-16 17:08:42 -0700530 } else if (!argv[1].equals("")) {
Barry Hayes0b3533a2010-01-20 12:46:47 -0800531 throw new RuntimeException(argv[0] + USAGE_STRING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 }
533
534 Log.i(TAG, "Accepting command socket connections");
535
536 if (ZYGOTE_FORK_MODE) {
537 runForkMode();
538 } else {
539 runSelectLoopMode();
540 }
541
542 closeServerSocket();
543 } catch (MethodAndArgsCaller caller) {
544 caller.run();
545 } catch (RuntimeException ex) {
546 Log.e(TAG, "Zygote died with exception", ex);
547 closeServerSocket();
548 throw ex;
549 }
550 }
551
552 /**
553 * Runs the zygote in accept-and-fork mode. In this mode, each peer
554 * gets its own zygote spawner process. This code is retained for
555 * reference only.
556 *
557 * @throws MethodAndArgsCaller in a child process when a main() should
558 * be executed.
559 */
560 private static void runForkMode() throws MethodAndArgsCaller {
561 while (true) {
562 ZygoteConnection peer = acceptCommandPeer();
563
564 int pid;
565
566 pid = Zygote.fork();
567
568 if (pid == 0) {
569 // The child process should handle the peer requests
570
571 // The child does not accept any more connections
572 try {
573 sServerSocket.close();
574 } catch (IOException ex) {
575 Log.e(TAG, "Zygote Child: error closing sockets", ex);
576 } finally {
577 sServerSocket = null;
578 }
579
580 peer.run();
581 break;
582 } else if (pid > 0) {
583 peer.closeSocket();
584 } else {
585 throw new RuntimeException("Error invoking fork()");
586 }
587 }
588 }
589
590 /**
591 * Runs the zygote process's select loop. Accepts new connections as
592 * they happen, and reads commands from connections one spawn-request's
593 * worth at a time.
594 *
595 * @throws MethodAndArgsCaller in a child process when a main() should
596 * be executed.
597 */
598 private static void runSelectLoopMode() throws MethodAndArgsCaller {
599 ArrayList<FileDescriptor> fds = new ArrayList();
600 ArrayList<ZygoteConnection> peers = new ArrayList();
601 FileDescriptor[] fdArray = new FileDescriptor[4];
602
603 fds.add(sServerSocket.getFileDescriptor());
604 peers.add(null);
605
606 int loopCount = GC_LOOP_COUNT;
607 while (true) {
608 int index;
609
610 /*
611 * Call gc() before we block in select().
612 * It's work that has to be done anyway, and it's better
613 * to avoid making every child do it. It will also
614 * madvise() any free memory as a side-effect.
615 *
616 * Don't call it every time, because walking the entire
617 * heap is a lot of overhead to free a few hundred bytes.
618 */
619 if (loopCount <= 0) {
620 gc();
621 loopCount = GC_LOOP_COUNT;
622 } else {
623 loopCount--;
624 }
625
626
627 try {
628 fdArray = fds.toArray(fdArray);
629 index = selectReadable(fdArray);
630 } catch (IOException ex) {
631 throw new RuntimeException("Error in select()", ex);
632 }
633
634 if (index < 0) {
635 throw new RuntimeException("Error in select()");
636 } else if (index == 0) {
637 ZygoteConnection newPeer = acceptCommandPeer();
638 peers.add(newPeer);
639 fds.add(newPeer.getFileDesciptor());
640 } else {
641 boolean done;
642 done = peers.get(index).runOnce();
643
644 if (done) {
645 peers.remove(index);
646 fds.remove(index);
647 }
648 }
649 }
650 }
651
652 /**
653 * The Linux syscall "setreuid()"
654 * @param ruid real uid
655 * @param euid effective uid
656 * @return 0 on success, non-zero errno on fail
657 */
658 static native int setreuid(int ruid, int euid);
659
660 /**
661 * The Linux syscall "setregid()"
662 * @param rgid real gid
663 * @param egid effective gid
664 * @return 0 on success, non-zero errno on fail
665 */
666 static native int setregid(int rgid, int egid);
667
668 /**
669 * Invokes the linux syscall "setpgid"
670 *
671 * @param pid pid to change
672 * @param pgid new process group of pid
673 * @return 0 on success or non-zero errno on fail
674 */
675 static native int setpgid(int pid, int pgid);
676
677 /**
678 * Invokes the linux syscall "getpgid"
679 *
680 * @param pid pid to query
681 * @return pgid of pid in question
682 * @throws IOException on error
683 */
684 static native int getpgid(int pid) throws IOException;
685
686 /**
687 * Invokes the syscall dup2() to copy the specified descriptors into
688 * stdin, stdout, and stderr. The existing stdio descriptors will be
689 * closed and errors during close will be ignored. The specified
690 * descriptors will also remain open at their original descriptor numbers,
691 * so the caller may want to close the original descriptors.
692 *
693 * @param in new stdin
694 * @param out new stdout
695 * @param err new stderr
696 * @throws IOException
697 */
698 static native void reopenStdio(FileDescriptor in,
699 FileDescriptor out, FileDescriptor err) throws IOException;
700
701 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800702 * Toggles the close-on-exec flag for the specified file descriptor.
703 *
704 * @param fd non-null; file descriptor
705 * @param flag desired close-on-exec flag state
706 * @throws IOException
707 */
708 static native void setCloseOnExec(FileDescriptor fd, boolean flag)
709 throws IOException;
710
711 /**
712 * Retrieves the permitted capability set from another process.
713 *
714 * @param pid &gt;=0 process ID or 0 for this process
715 * @throws IOException on error
716 */
717 static native long capgetPermitted(int pid)
718 throws IOException;
719
720 /**
721 * Sets the permitted and effective capability sets of this process.
722 *
723 * @param permittedCapabilities permitted set
724 * @param effectiveCapabilities effective set
725 * @throws IOException on error
726 */
727 static native void setCapabilities(
728 long permittedCapabilities,
729 long effectiveCapabilities) throws IOException;
730
731 /**
732 * Invokes select() on the provider array of file descriptors (selecting
733 * for readability only). Array elements of null are ignored.
734 *
735 * @param fds non-null; array of readable file descriptors
736 * @return index of descriptor that is now readable or -1 for empty array.
737 * @throws IOException if an error occurs
738 */
739 static native int selectReadable(FileDescriptor[] fds) throws IOException;
740
741 /**
742 * Creates a file descriptor from an int fd.
743 *
744 * @param fd integer OS file descriptor
745 * @return non-null; FileDescriptor instance
746 * @throws IOException if fd is invalid
747 */
748 static native FileDescriptor createFileDescriptor(int fd)
749 throws IOException;
750
751 /**
752 * Class not instantiable.
753 */
754 private ZygoteInit() {
755 }
756
757 /**
758 * Helper exception class which holds a method and arguments and
759 * can call them. This is used as part of a trampoline to get rid of
760 * the initial process setup stack frames.
761 */
762 public static class MethodAndArgsCaller extends Exception
763 implements Runnable {
764 /** method to call */
765 private final Method mMethod;
766
767 /** argument array */
768 private final String[] mArgs;
769
770 public MethodAndArgsCaller(Method method, String[] args) {
771 mMethod = method;
772 mArgs = args;
773 }
774
775 public void run() {
776 try {
777 mMethod.invoke(null, new Object[] { mArgs });
778 } catch (IllegalAccessException ex) {
779 throw new RuntimeException(ex);
780 } catch (InvocationTargetException ex) {
781 Throwable cause = ex.getCause();
782 if (cause instanceof RuntimeException) {
783 throw (RuntimeException) cause;
784 } else if (cause instanceof Error) {
785 throw (Error) cause;
786 }
787 throw new RuntimeException(ex);
788 }
789 }
790 }
791}