blob: fbe66e5001ca609ac7d212819ca538ee69529135 [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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.os.SystemClock;
27import android.os.SystemProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.util.EventLog;
29import android.util.Log;
30
31import dalvik.system.VMRuntime;
32import dalvik.system.Zygote;
33
Brian Carlstrom46703b02011-04-06 15:41:29 -070034import libcore.io.IoUtils;
35
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import java.io.BufferedReader;
37import java.io.FileDescriptor;
38import java.io.IOException;
39import java.io.InputStream;
40import java.io.InputStreamReader;
41import java.lang.reflect.InvocationTargetException;
42import java.lang.reflect.Method;
43import java.lang.reflect.Modifier;
44import java.util.ArrayList;
45
46/**
47 * Startup class for the zygote process.
48 *
49 * Pre-initializes some classes, and then waits for commands on a UNIX domain
50 * socket. Based on these commands, forks of child processes that inherit
51 * the initial state of the VM.
52 *
53 * Please see {@link ZygoteConnection.Arguments} for documentation on the
54 * client protocol.
55 *
56 * @hide
57 */
58public class ZygoteInit {
59
60 private static final String TAG = "Zygote";
61
62 private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";
63
64 private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
65 private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
66
67 /** when preloading, GC after allocating this many bytes */
68 private static final int PRELOAD_GC_THRESHOLD = 50000;
69
Barry Hayes0b3533a2010-01-20 12:46:47 -080070 public static final String USAGE_STRING =
71 " <\"true\"|\"false\" for startSystemServer>";
72
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073 private static LocalServerSocket sServerSocket;
74
75 /**
76 * Used to pre-load resources. We hold a global reference on it so it
77 * never gets destroyed.
78 */
79 private static Resources mResources;
Bob Leee5408332009-09-04 18:31:17 -070080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 /**
82 * The number of times that the main Zygote loop
83 * should run before calling gc() again.
84 */
85 static final int GC_LOOP_COUNT = 10;
86
87 /**
88 * If true, zygote forks for each peer. If false, a select loop is used
89 * inside a single process. The latter is preferred.
90 */
91 private static final boolean ZYGOTE_FORK_MODE = false;
92
93 /**
94 * The name of a resource file that contains classes to preload.
95 */
96 private static final String PRELOADED_CLASSES = "preloaded-classes";
97
98 /** Controls whether we should preload resources during zygote init. */
99 private static final boolean PRELOAD_RESOURCES = true;
Andy McFadden599c9182009-04-08 00:35:56 -0700100
101 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 * Invokes a static "main(argv[]) method on class "className".
103 * Converts various failing exceptions into RuntimeExceptions, with
104 * the assumption that they will then cause the VM instance to exit.
105 *
106 * @param loader class loader to use
107 * @param className Fully-qualified class name
108 * @param argv Argument vector for main()
109 */
110 static void invokeStaticMain(ClassLoader loader,
111 String className, String[] argv)
112 throws ZygoteInit.MethodAndArgsCaller {
113 Class<?> cl;
114
115 try {
116 cl = loader.loadClass(className);
117 } catch (ClassNotFoundException ex) {
118 throw new RuntimeException(
119 "Missing class when invoking static main " + className,
120 ex);
121 }
122
123 Method m;
124 try {
125 m = cl.getMethod("main", new Class[] { String[].class });
126 } catch (NoSuchMethodException ex) {
127 throw new RuntimeException(
128 "Missing static main on " + className, ex);
129 } catch (SecurityException ex) {
130 throw new RuntimeException(
131 "Problem getting static main on " + className, ex);
132 }
133
134 int modifiers = m.getModifiers();
135 if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
136 throw new RuntimeException(
137 "Main method is not public and static on " + className);
138 }
139
140 /*
141 * This throw gets caught in ZygoteInit.main(), which responds
142 * by invoking the exception's run() method. This arrangement
143 * clears up all the stack frames that were required in setting
144 * up the process.
145 */
146 throw new ZygoteInit.MethodAndArgsCaller(m, argv);
147 }
148
149 /**
150 * Registers a server socket for zygote command connections
151 *
152 * @throws RuntimeException when open fails
153 */
154 private static void registerZygoteSocket() {
155 if (sServerSocket == null) {
156 int fileDesc;
157 try {
158 String env = System.getenv(ANDROID_SOCKET_ENV);
159 fileDesc = Integer.parseInt(env);
160 } catch (RuntimeException ex) {
161 throw new RuntimeException(
162 ANDROID_SOCKET_ENV + " unset or invalid", ex);
163 }
164
165 try {
166 sServerSocket = new LocalServerSocket(
167 createFileDescriptor(fileDesc));
168 } catch (IOException ex) {
169 throw new RuntimeException(
170 "Error binding to local socket '" + fileDesc + "'", ex);
171 }
172 }
173 }
174
175 /**
176 * Waits for and accepts a single command connection. Throws
177 * RuntimeException on failure.
178 */
179 private static ZygoteConnection acceptCommandPeer() {
Bob Leee5408332009-09-04 18:31:17 -0700180 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 return new ZygoteConnection(sServerSocket.accept());
182 } catch (IOException ex) {
183 throw new RuntimeException(
184 "IOException during accept()", ex);
185 }
186 }
187
188 /**
189 * Close and clean up zygote sockets. Called on shutdown and on the
190 * child's exit path.
191 */
192 static void closeServerSocket() {
193 try {
194 if (sServerSocket != null) {
195 sServerSocket.close();
196 }
197 } catch (IOException ex) {
198 Log.e(TAG, "Zygote: error closing sockets", ex);
199 }
200
201 sServerSocket = null;
202 }
203
204 private static final int UNPRIVILEGED_UID = 9999;
205 private static final int UNPRIVILEGED_GID = 9999;
206
207 private static final int ROOT_UID = 0;
208 private static final int ROOT_GID = 0;
209
210 /**
211 * Sets effective user ID.
212 */
213 private static void setEffectiveUser(int uid) {
214 int errno = setreuid(ROOT_UID, uid);
215 if (errno != 0) {
216 Log.e(TAG, "setreuid() failed. errno: " + errno);
217 }
218 }
219
220 /**
221 * Sets effective group ID.
222 */
223 private static void setEffectiveGroup(int gid) {
224 int errno = setregid(ROOT_GID, gid);
225 if (errno != 0) {
226 Log.e(TAG, "setregid() failed. errno: " + errno);
227 }
228 }
229
230 /**
231 * Performs Zygote process initialization. Loads and initializes
232 * commonly used classes.
233 *
234 * Most classes only cause a few hundred bytes to be allocated, but
235 * a few will allocate a dozen Kbytes (in one case, 500+K).
236 */
237 private static void preloadClasses() {
238 final VMRuntime runtime = VMRuntime.getRuntime();
Bob Leee5408332009-09-04 18:31:17 -0700239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 InputStream is = ZygoteInit.class.getClassLoader().getResourceAsStream(
241 PRELOADED_CLASSES);
242 if (is == null) {
243 Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
244 } else {
245 Log.i(TAG, "Preloading classes...");
246 long startTime = SystemClock.uptimeMillis();
Bob Leee5408332009-09-04 18:31:17 -0700247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 // Drop root perms while running static initializers.
249 setEffectiveGroup(UNPRIVILEGED_GID);
250 setEffectiveUser(UNPRIVILEGED_UID);
251
252 // Alter the target heap utilization. With explicit GCs this
253 // is not likely to have any effect.
254 float defaultUtilization = runtime.getTargetHeapUtilization();
255 runtime.setTargetHeapUtilization(0.8f);
256
257 // Start with a clean slate.
Brian Carlstrom08065b92011-04-01 15:49:41 -0700258 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 runtime.runFinalizationSync();
260 Debug.startAllocCounting();
261
262 try {
Bob Leee5408332009-09-04 18:31:17 -0700263 BufferedReader br
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 = new BufferedReader(new InputStreamReader(is), 256);
265
266 int count = 0;
267 String line;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 while ((line = br.readLine()) != null) {
269 // Skip comments and blank lines.
270 line = line.trim();
271 if (line.startsWith("#") || line.equals("")) {
272 continue;
273 }
274
275 try {
Joe Onorato43a17652011-04-06 19:22:23 -0700276 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277 Log.v(TAG, "Preloading " + line + "...");
278 }
279 Class.forName(line);
280 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700281 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 Log.v(TAG,
283 " GC at " + Debug.getGlobalAllocSize());
284 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700285 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 runtime.runFinalizationSync();
287 Debug.resetGlobalAllocSize();
288 }
289 count++;
290 } catch (ClassNotFoundException e) {
Jesse Wilsone2417542010-06-03 12:33:26 -0700291 Log.w(TAG, "Class not found for preloading: " + line);
Bob Lee2e93f652009-08-11 01:16:03 -0700292 } catch (Throwable t) {
293 Log.e(TAG, "Error preloading " + line + ".", t);
294 if (t instanceof Error) {
295 throw (Error) t;
296 }
297 if (t instanceof RuntimeException) {
298 throw (RuntimeException) t;
299 }
300 throw new RuntimeException(t);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 }
302 }
303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 Log.i(TAG, "...preloaded " + count + " classes in "
305 + (SystemClock.uptimeMillis()-startTime) + "ms.");
306 } catch (IOException e) {
307 Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
308 } finally {
Brian Carlstrom46703b02011-04-06 15:41:29 -0700309 IoUtils.closeQuietly(is);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 // Restore default.
311 runtime.setTargetHeapUtilization(defaultUtilization);
312
313 Debug.stopAllocCounting();
314
315 // Bring back root. We'll need it later.
316 setEffectiveUser(ROOT_UID);
317 setEffectiveGroup(ROOT_GID);
318 }
319 }
320 }
321
322 /**
323 * Load in commonly used resources, so they can be shared across
324 * processes.
325 *
326 * These tend to be a few Kbytes, but are frequently in the 20-40K
327 * range, and occasionally even larger.
328 */
329 private static void preloadResources() {
330 final VMRuntime runtime = VMRuntime.getRuntime();
Bob Leee5408332009-09-04 18:31:17 -0700331
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 Debug.startAllocCounting();
333 try {
Brian Carlstrom08065b92011-04-01 15:49:41 -0700334 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 runtime.runFinalizationSync();
336 mResources = Resources.getSystem();
337 mResources.startPreloading();
338 if (PRELOAD_RESOURCES) {
339 Log.i(TAG, "Preloading resources...");
340
341 long startTime = SystemClock.uptimeMillis();
342 TypedArray ar = mResources.obtainTypedArray(
343 com.android.internal.R.array.preloaded_drawables);
344 int N = preloadDrawables(runtime, ar);
345 Log.i(TAG, "...preloaded " + N + " resources in "
346 + (SystemClock.uptimeMillis()-startTime) + "ms.");
347
348 startTime = SystemClock.uptimeMillis();
349 ar = mResources.obtainTypedArray(
350 com.android.internal.R.array.preloaded_color_state_lists);
351 N = preloadColorStateLists(runtime, ar);
352 Log.i(TAG, "...preloaded " + N + " resources in "
353 + (SystemClock.uptimeMillis()-startTime) + "ms.");
354 }
355 mResources.finishPreloading();
356 } catch (RuntimeException e) {
357 Log.w(TAG, "Failure preloading resources", e);
358 } finally {
359 Debug.stopAllocCounting();
360 }
361 }
362
363 private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) {
364 int N = ar.length();
365 for (int i=0; i<N; i++) {
366 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700367 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
369 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700370 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 runtime.runFinalizationSync();
372 Debug.resetGlobalAllocSize();
373 }
374 int id = ar.getResourceId(i, 0);
Joe Onorato43a17652011-04-06 19:22:23 -0700375 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
377 }
378 if (id != 0) {
379 mResources.getColorStateList(id);
380 }
381 }
382 return N;
383 }
384
385
386 private static int preloadDrawables(VMRuntime runtime, TypedArray ar) {
387 int N = ar.length();
388 for (int i=0; i<N; i++) {
389 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700390 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
392 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700393 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 runtime.runFinalizationSync();
395 Debug.resetGlobalAllocSize();
396 }
397 int id = ar.getResourceId(i, 0);
Joe Onorato43a17652011-04-06 19:22:23 -0700398 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
400 }
401 if (id != 0) {
402 Drawable dr = mResources.getDrawable(id);
403 if ((dr.getChangingConfigurations()&~ActivityInfo.CONFIG_FONT_SCALE) != 0) {
404 Log.w(TAG, "Preloaded drawable resource #0x"
405 + Integer.toHexString(id)
406 + " (" + ar.getString(i) + ") that varies with configuration!!");
407 }
408 }
409 }
410 return N;
411 }
412
413 /**
414 * Runs several special GCs to try to clean up a few generations of
415 * softly- and final-reachable objects, along with any other garbage.
416 * This is only useful just before a fork().
417 */
418 /*package*/ static void gc() {
419 final VMRuntime runtime = VMRuntime.getRuntime();
420
421 /* runFinalizationSync() lets finalizers be called in Zygote,
422 * which doesn't have a HeapWorker thread.
423 */
Brian Carlstrom08065b92011-04-01 15:49:41 -0700424 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425 runtime.runFinalizationSync();
Brian Carlstrom08065b92011-04-01 15:49:41 -0700426 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 runtime.runFinalizationSync();
Brian Carlstrom08065b92011-04-01 15:49:41 -0700428 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 runtime.runFinalizationSync();
430 }
431
432 /**
433 * Finish remaining work for the newly forked system server process.
434 */
435 private static void handleSystemServerProcess(
436 ZygoteConnection.Arguments parsedArgs)
437 throws ZygoteInit.MethodAndArgsCaller {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438
439 closeServerSocket();
440
Mike Lockwood90960e82010-08-06 09:15:25 -0400441 // set umask to 0077 so new files and directories will default to owner-only permissions.
442 FileUtils.setUMask(FileUtils.S_IRWXG | FileUtils.S_IRWXO);
443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 /*
445 * Pass the remaining arguments to SystemServer.
446 * "--nice-name=system_server com.android.server.SystemServer"
447 */
448 RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
449 /* should never reach here */
450 }
451
452 /**
453 * Prepare the arguments and fork for the system server process.
454 */
Bob Leee5408332009-09-04 18:31:17 -0700455 private static boolean startSystemServer()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 throws MethodAndArgsCaller, RuntimeException {
457 /* Hardcoded command line to start the system server */
458 String args[] = {
459 "--setuid=1000",
460 "--setgid=1000",
Mike Lockwood037a0862010-07-27 18:42:44 -0400461 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003",
San Mehat1caefa62009-06-10 09:09:51 -0700462 "--capabilities=130104352,130104352",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 "--runtime-init",
464 "--nice-name=system_server",
465 "com.android.server.SystemServer",
466 };
467 ZygoteConnection.Arguments parsedArgs = null;
468
469 int pid;
470
471 try {
472 parsedArgs = new ZygoteConnection.Arguments(args);
473
474 /*
475 * Enable debugging of the system process if *either* the command line flags
476 * indicate it should be debuggable or the ro.debuggable system property
477 * is set to "1"
478 */
479 int debugFlags = parsedArgs.debugFlags;
480 if ("1".equals(SystemProperties.get("ro.debuggable")))
481 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
482
483 /* Request to fork the system server process */
484 pid = Zygote.forkSystemServer(
485 parsedArgs.uid, parsedArgs.gid,
Andy McFadden1b4c7962010-10-27 11:26:05 -0700486 parsedArgs.gids, debugFlags, null,
487 parsedArgs.permittedCapabilities,
488 parsedArgs.effectiveCapabilities);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 } catch (IllegalArgumentException ex) {
490 throw new RuntimeException(ex);
Bob Leee5408332009-09-04 18:31:17 -0700491 }
492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 /* For child process */
494 if (pid == 0) {
495 handleSystemServerProcess(parsedArgs);
496 }
497
498 return true;
499 }
500
501 public static void main(String argv[]) {
502 try {
Bob Leee5408332009-09-04 18:31:17 -0700503 // Start profiling the zygote initialization.
504 SamplingProfilerIntegration.start();
505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 registerZygoteSocket();
507 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
508 SystemClock.uptimeMillis());
509 preloadClasses();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 preloadResources();
511 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
512 SystemClock.uptimeMillis());
513
Brian Carlstrom17510862010-08-18 14:27:40 -0700514 // Finish profiling the zygote initialization.
515 SamplingProfilerIntegration.writeZygoteSnapshot();
Bob Leee5408332009-09-04 18:31:17 -0700516
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 // Do an initial gc to clean up after startup
518 gc();
519
520 // If requested, start system server directly from Zygote
521 if (argv.length != 2) {
Barry Hayes0b3533a2010-01-20 12:46:47 -0800522 throw new RuntimeException(argv[0] + USAGE_STRING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 }
524
525 if (argv[1].equals("true")) {
526 startSystemServer();
Barry Hayes0b3533a2010-01-20 12:46:47 -0800527 } else if (!argv[1].equals("false")) {
528 throw new RuntimeException(argv[0] + USAGE_STRING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 }
530
531 Log.i(TAG, "Accepting command socket connections");
532
533 if (ZYGOTE_FORK_MODE) {
534 runForkMode();
535 } else {
536 runSelectLoopMode();
537 }
538
539 closeServerSocket();
540 } catch (MethodAndArgsCaller caller) {
541 caller.run();
542 } catch (RuntimeException ex) {
543 Log.e(TAG, "Zygote died with exception", ex);
544 closeServerSocket();
545 throw ex;
546 }
547 }
548
549 /**
550 * Runs the zygote in accept-and-fork mode. In this mode, each peer
551 * gets its own zygote spawner process. This code is retained for
552 * reference only.
553 *
554 * @throws MethodAndArgsCaller in a child process when a main() should
555 * be executed.
556 */
557 private static void runForkMode() throws MethodAndArgsCaller {
558 while (true) {
559 ZygoteConnection peer = acceptCommandPeer();
560
561 int pid;
562
563 pid = Zygote.fork();
564
565 if (pid == 0) {
566 // The child process should handle the peer requests
567
568 // The child does not accept any more connections
569 try {
570 sServerSocket.close();
571 } catch (IOException ex) {
572 Log.e(TAG, "Zygote Child: error closing sockets", ex);
573 } finally {
574 sServerSocket = null;
575 }
576
577 peer.run();
578 break;
579 } else if (pid > 0) {
580 peer.closeSocket();
581 } else {
582 throw new RuntimeException("Error invoking fork()");
583 }
584 }
585 }
586
587 /**
588 * Runs the zygote process's select loop. Accepts new connections as
589 * they happen, and reads commands from connections one spawn-request's
590 * worth at a time.
591 *
592 * @throws MethodAndArgsCaller in a child process when a main() should
593 * be executed.
594 */
595 private static void runSelectLoopMode() throws MethodAndArgsCaller {
596 ArrayList<FileDescriptor> fds = new ArrayList();
597 ArrayList<ZygoteConnection> peers = new ArrayList();
598 FileDescriptor[] fdArray = new FileDescriptor[4];
599
600 fds.add(sServerSocket.getFileDescriptor());
601 peers.add(null);
602
603 int loopCount = GC_LOOP_COUNT;
604 while (true) {
605 int index;
606
607 /*
608 * Call gc() before we block in select().
609 * It's work that has to be done anyway, and it's better
610 * to avoid making every child do it. It will also
611 * madvise() any free memory as a side-effect.
612 *
613 * Don't call it every time, because walking the entire
614 * heap is a lot of overhead to free a few hundred bytes.
615 */
616 if (loopCount <= 0) {
617 gc();
618 loopCount = GC_LOOP_COUNT;
619 } else {
620 loopCount--;
621 }
622
623
624 try {
625 fdArray = fds.toArray(fdArray);
626 index = selectReadable(fdArray);
627 } catch (IOException ex) {
628 throw new RuntimeException("Error in select()", ex);
629 }
630
631 if (index < 0) {
632 throw new RuntimeException("Error in select()");
633 } else if (index == 0) {
634 ZygoteConnection newPeer = acceptCommandPeer();
635 peers.add(newPeer);
636 fds.add(newPeer.getFileDesciptor());
637 } else {
638 boolean done;
639 done = peers.get(index).runOnce();
640
641 if (done) {
642 peers.remove(index);
643 fds.remove(index);
644 }
645 }
646 }
647 }
648
649 /**
650 * The Linux syscall "setreuid()"
651 * @param ruid real uid
652 * @param euid effective uid
653 * @return 0 on success, non-zero errno on fail
654 */
655 static native int setreuid(int ruid, int euid);
656
657 /**
658 * The Linux syscall "setregid()"
659 * @param rgid real gid
660 * @param egid effective gid
661 * @return 0 on success, non-zero errno on fail
662 */
663 static native int setregid(int rgid, int egid);
664
665 /**
666 * Invokes the linux syscall "setpgid"
667 *
668 * @param pid pid to change
669 * @param pgid new process group of pid
670 * @return 0 on success or non-zero errno on fail
671 */
672 static native int setpgid(int pid, int pgid);
673
674 /**
675 * Invokes the linux syscall "getpgid"
676 *
677 * @param pid pid to query
678 * @return pgid of pid in question
679 * @throws IOException on error
680 */
681 static native int getpgid(int pid) throws IOException;
682
683 /**
684 * Invokes the syscall dup2() to copy the specified descriptors into
685 * stdin, stdout, and stderr. The existing stdio descriptors will be
686 * closed and errors during close will be ignored. The specified
687 * descriptors will also remain open at their original descriptor numbers,
688 * so the caller may want to close the original descriptors.
689 *
690 * @param in new stdin
691 * @param out new stdout
692 * @param err new stderr
693 * @throws IOException
694 */
695 static native void reopenStdio(FileDescriptor in,
696 FileDescriptor out, FileDescriptor err) throws IOException;
697
698 /**
699 * Calls close() on a file descriptor
700 *
701 * @param fd descriptor to close
702 * @throws IOException
703 */
704 static native void closeDescriptor(FileDescriptor fd)
705 throws IOException;
706
707 /**
708 * Toggles the close-on-exec flag for the specified file descriptor.
709 *
710 * @param fd non-null; file descriptor
711 * @param flag desired close-on-exec flag state
712 * @throws IOException
713 */
714 static native void setCloseOnExec(FileDescriptor fd, boolean flag)
715 throws IOException;
716
717 /**
718 * Retrieves the permitted capability set from another process.
719 *
720 * @param pid &gt;=0 process ID or 0 for this process
721 * @throws IOException on error
722 */
723 static native long capgetPermitted(int pid)
724 throws IOException;
725
726 /**
727 * Sets the permitted and effective capability sets of this process.
728 *
729 * @param permittedCapabilities permitted set
730 * @param effectiveCapabilities effective set
731 * @throws IOException on error
732 */
733 static native void setCapabilities(
734 long permittedCapabilities,
735 long effectiveCapabilities) throws IOException;
736
737 /**
738 * Invokes select() on the provider array of file descriptors (selecting
739 * for readability only). Array elements of null are ignored.
740 *
741 * @param fds non-null; array of readable file descriptors
742 * @return index of descriptor that is now readable or -1 for empty array.
743 * @throws IOException if an error occurs
744 */
745 static native int selectReadable(FileDescriptor[] fds) throws IOException;
746
747 /**
748 * Creates a file descriptor from an int fd.
749 *
750 * @param fd integer OS file descriptor
751 * @return non-null; FileDescriptor instance
752 * @throws IOException if fd is invalid
753 */
754 static native FileDescriptor createFileDescriptor(int fd)
755 throws IOException;
756
757 /**
758 * Class not instantiable.
759 */
760 private ZygoteInit() {
761 }
762
763 /**
764 * Helper exception class which holds a method and arguments and
765 * can call them. This is used as part of a trampoline to get rid of
766 * the initial process setup stack frames.
767 */
768 public static class MethodAndArgsCaller extends Exception
769 implements Runnable {
770 /** method to call */
771 private final Method mMethod;
772
773 /** argument array */
774 private final String[] mArgs;
775
776 public MethodAndArgsCaller(Method method, String[] args) {
777 mMethod = method;
778 mArgs = args;
779 }
780
781 public void run() {
782 try {
783 mMethod.invoke(null, new Object[] { mArgs });
784 } catch (IllegalAccessException ex) {
785 throw new RuntimeException(ex);
786 } catch (InvocationTargetException ex) {
787 Throwable cause = ex.getCause();
788 if (cause instanceof RuntimeException) {
789 throw (RuntimeException) cause;
790 } else if (cause instanceof Error) {
791 throw (Error) cause;
792 }
793 throw new RuntimeException(ex);
794 }
795 }
796 }
797}