blob: 4c82ce80a080eca21ac9e2dec5d3103146c02319 [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
Kenny Root4c74f8c2012-08-17 08:45:55 -070019import static libcore.io.OsConstants.S_IRWXG;
20import static libcore.io.OsConstants.S_IRWXO;
21
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.res.Resources;
23import android.content.res.TypedArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.net.LocalServerSocket;
25import android.os.Debug;
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;
Jamie Gennis6ad04522013-04-15 18:53:24 -070028import android.os.Trace;
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;
Kenny Root4c74f8c2012-08-17 08:45:55 -070036import libcore.io.Libcore;
Alex Klyubin48a06e72013-04-19 10:01:42 -070037import libcore.io.OsConstants;
Brian Carlstrom46703b02011-04-06 15:41:29 -070038
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import java.io.BufferedReader;
40import java.io.FileDescriptor;
41import java.io.IOException;
42import java.io.InputStream;
43import java.io.InputStreamReader;
44import java.lang.reflect.InvocationTargetException;
45import java.lang.reflect.Method;
46import java.lang.reflect.Modifier;
47import java.util.ArrayList;
48
49/**
50 * Startup class for the zygote process.
51 *
52 * Pre-initializes some classes, and then waits for commands on a UNIX domain
Elliott Hughese1dfcb72011-07-08 11:08:07 -070053 * socket. Based on these commands, forks off child processes that inherit
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054 * the initial state of the VM.
55 *
56 * Please see {@link ZygoteConnection.Arguments} for documentation on the
57 * client protocol.
58 *
59 * @hide
60 */
61public class ZygoteInit {
62
63 private static final String TAG = "Zygote";
64
65 private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";
66
67 private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
68 private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
69
70 /** when preloading, GC after allocating this many bytes */
71 private static final int PRELOAD_GC_THRESHOLD = 50000;
72
Barry Hayes0b3533a2010-01-20 12:46:47 -080073 public static final String USAGE_STRING =
Jeff Brownebed7d62011-05-16 17:08:42 -070074 " <\"start-system-server\"|\"\" for startSystemServer>";
Barry Hayes0b3533a2010-01-20 12:46:47 -080075
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 private static LocalServerSocket sServerSocket;
77
78 /**
79 * Used to pre-load resources. We hold a global reference on it so it
80 * never gets destroyed.
81 */
82 private static Resources mResources;
Bob Leee5408332009-09-04 18:31:17 -070083
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 /**
85 * The number of times that the main Zygote loop
86 * should run before calling gc() again.
87 */
88 static final int GC_LOOP_COUNT = 10;
89
90 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 * The name of a resource file that contains classes to preload.
92 */
93 private static final String PRELOADED_CLASSES = "preloaded-classes";
94
95 /** Controls whether we should preload resources during zygote init. */
96 private static final boolean PRELOAD_RESOURCES = true;
Andy McFadden599c9182009-04-08 00:35:56 -070097
98 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 * Invokes a static "main(argv[]) method on class "className".
100 * Converts various failing exceptions into RuntimeExceptions, with
101 * the assumption that they will then cause the VM instance to exit.
102 *
103 * @param loader class loader to use
104 * @param className Fully-qualified class name
105 * @param argv Argument vector for main()
106 */
107 static void invokeStaticMain(ClassLoader loader,
108 String className, String[] argv)
109 throws ZygoteInit.MethodAndArgsCaller {
110 Class<?> cl;
111
112 try {
113 cl = loader.loadClass(className);
114 } catch (ClassNotFoundException ex) {
115 throw new RuntimeException(
116 "Missing class when invoking static main " + className,
117 ex);
118 }
119
120 Method m;
121 try {
122 m = cl.getMethod("main", new Class[] { String[].class });
123 } catch (NoSuchMethodException ex) {
124 throw new RuntimeException(
125 "Missing static main on " + className, ex);
126 } catch (SecurityException ex) {
127 throw new RuntimeException(
128 "Problem getting static main on " + className, ex);
129 }
130
131 int modifiers = m.getModifiers();
132 if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
133 throw new RuntimeException(
134 "Main method is not public and static on " + className);
135 }
136
137 /*
138 * This throw gets caught in ZygoteInit.main(), which responds
139 * by invoking the exception's run() method. This arrangement
140 * clears up all the stack frames that were required in setting
141 * up the process.
142 */
143 throw new ZygoteInit.MethodAndArgsCaller(m, argv);
144 }
145
146 /**
147 * Registers a server socket for zygote command connections
148 *
149 * @throws RuntimeException when open fails
150 */
151 private static void registerZygoteSocket() {
152 if (sServerSocket == null) {
153 int fileDesc;
154 try {
155 String env = System.getenv(ANDROID_SOCKET_ENV);
156 fileDesc = Integer.parseInt(env);
157 } catch (RuntimeException ex) {
158 throw new RuntimeException(
159 ANDROID_SOCKET_ENV + " unset or invalid", ex);
160 }
161
162 try {
163 sServerSocket = new LocalServerSocket(
164 createFileDescriptor(fileDesc));
165 } catch (IOException ex) {
166 throw new RuntimeException(
167 "Error binding to local socket '" + fileDesc + "'", ex);
168 }
169 }
170 }
171
172 /**
173 * Waits for and accepts a single command connection. Throws
174 * RuntimeException on failure.
175 */
176 private static ZygoteConnection acceptCommandPeer() {
Bob Leee5408332009-09-04 18:31:17 -0700177 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 return new ZygoteConnection(sServerSocket.accept());
179 } catch (IOException ex) {
180 throw new RuntimeException(
181 "IOException during accept()", ex);
182 }
183 }
184
185 /**
186 * Close and clean up zygote sockets. Called on shutdown and on the
187 * child's exit path.
188 */
189 static void closeServerSocket() {
190 try {
191 if (sServerSocket != null) {
192 sServerSocket.close();
193 }
194 } catch (IOException ex) {
195 Log.e(TAG, "Zygote: error closing sockets", ex);
196 }
197
198 sServerSocket = null;
199 }
200
201 private static final int UNPRIVILEGED_UID = 9999;
202 private static final int UNPRIVILEGED_GID = 9999;
203
204 private static final int ROOT_UID = 0;
205 private static final int ROOT_GID = 0;
206
207 /**
208 * Sets effective user ID.
209 */
210 private static void setEffectiveUser(int uid) {
211 int errno = setreuid(ROOT_UID, uid);
212 if (errno != 0) {
213 Log.e(TAG, "setreuid() failed. errno: " + errno);
214 }
215 }
216
217 /**
218 * Sets effective group ID.
219 */
220 private static void setEffectiveGroup(int gid) {
221 int errno = setregid(ROOT_GID, gid);
222 if (errno != 0) {
223 Log.e(TAG, "setregid() failed. errno: " + errno);
224 }
225 }
226
Jeff Brown0c2313d2011-06-10 22:46:40 -0700227 static void preload() {
228 preloadClasses();
229 preloadResources();
230 }
231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 /**
233 * Performs Zygote process initialization. Loads and initializes
234 * commonly used classes.
235 *
236 * Most classes only cause a few hundred bytes to be allocated, but
237 * a few will allocate a dozen Kbytes (in one case, 500+K).
238 */
239 private static void preloadClasses() {
240 final VMRuntime runtime = VMRuntime.getRuntime();
Bob Leee5408332009-09-04 18:31:17 -0700241
Andy McFaddendc7bf5d2012-01-23 09:48:53 -0800242 InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 PRELOADED_CLASSES);
244 if (is == null) {
245 Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
246 } else {
247 Log.i(TAG, "Preloading classes...");
248 long startTime = SystemClock.uptimeMillis();
Bob Leee5408332009-09-04 18:31:17 -0700249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 // Drop root perms while running static initializers.
251 setEffectiveGroup(UNPRIVILEGED_GID);
252 setEffectiveUser(UNPRIVILEGED_UID);
253
254 // Alter the target heap utilization. With explicit GCs this
255 // is not likely to have any effect.
256 float defaultUtilization = runtime.getTargetHeapUtilization();
257 runtime.setTargetHeapUtilization(0.8f);
258
259 // Start with a clean slate.
Brian Carlstrom08065b92011-04-01 15:49:41 -0700260 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 runtime.runFinalizationSync();
262 Debug.startAllocCounting();
263
264 try {
Bob Leee5408332009-09-04 18:31:17 -0700265 BufferedReader br
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 = new BufferedReader(new InputStreamReader(is), 256);
267
268 int count = 0;
269 String line;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 while ((line = br.readLine()) != null) {
271 // Skip comments and blank lines.
272 line = line.trim();
273 if (line.startsWith("#") || line.equals("")) {
274 continue;
275 }
276
277 try {
Joe Onorato43a17652011-04-06 19:22:23 -0700278 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 Log.v(TAG, "Preloading " + line + "...");
280 }
281 Class.forName(line);
282 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700283 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 Log.v(TAG,
285 " GC at " + Debug.getGlobalAllocSize());
286 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700287 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 runtime.runFinalizationSync();
289 Debug.resetGlobalAllocSize();
290 }
291 count++;
292 } catch (ClassNotFoundException e) {
Jesse Wilsone2417542010-06-03 12:33:26 -0700293 Log.w(TAG, "Class not found for preloading: " + line);
Brian Carlstromad13bd52013-11-03 22:47:11 -0800294 } catch (UnsatisfiedLinkError e) {
295 Log.w(TAG, "Problem preloading " + line + ": " + e);
Bob Lee2e93f652009-08-11 01:16:03 -0700296 } catch (Throwable t) {
297 Log.e(TAG, "Error preloading " + line + ".", t);
298 if (t instanceof Error) {
299 throw (Error) t;
300 }
301 if (t instanceof RuntimeException) {
302 throw (RuntimeException) t;
303 }
304 throw new RuntimeException(t);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 }
306 }
307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 Log.i(TAG, "...preloaded " + count + " classes in "
309 + (SystemClock.uptimeMillis()-startTime) + "ms.");
310 } catch (IOException e) {
311 Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
312 } finally {
Brian Carlstrom46703b02011-04-06 15:41:29 -0700313 IoUtils.closeQuietly(is);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 // Restore default.
315 runtime.setTargetHeapUtilization(defaultUtilization);
316
317 Debug.stopAllocCounting();
318
319 // Bring back root. We'll need it later.
320 setEffectiveUser(ROOT_UID);
321 setEffectiveGroup(ROOT_GID);
322 }
323 }
324 }
325
326 /**
327 * Load in commonly used resources, so they can be shared across
328 * processes.
329 *
330 * These tend to be a few Kbytes, but are frequently in the 20-40K
331 * range, and occasionally even larger.
332 */
333 private static void preloadResources() {
334 final VMRuntime runtime = VMRuntime.getRuntime();
Bob Leee5408332009-09-04 18:31:17 -0700335
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 Debug.startAllocCounting();
337 try {
Brian Carlstrom08065b92011-04-01 15:49:41 -0700338 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 runtime.runFinalizationSync();
340 mResources = Resources.getSystem();
341 mResources.startPreloading();
342 if (PRELOAD_RESOURCES) {
343 Log.i(TAG, "Preloading resources...");
344
345 long startTime = SystemClock.uptimeMillis();
346 TypedArray ar = mResources.obtainTypedArray(
347 com.android.internal.R.array.preloaded_drawables);
348 int N = preloadDrawables(runtime, ar);
Jeff Brown14577c42012-03-08 16:40:14 -0800349 ar.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 Log.i(TAG, "...preloaded " + N + " resources in "
351 + (SystemClock.uptimeMillis()-startTime) + "ms.");
352
353 startTime = SystemClock.uptimeMillis();
354 ar = mResources.obtainTypedArray(
355 com.android.internal.R.array.preloaded_color_state_lists);
356 N = preloadColorStateLists(runtime, ar);
Jeff Brown14577c42012-03-08 16:40:14 -0800357 ar.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 Log.i(TAG, "...preloaded " + N + " resources in "
359 + (SystemClock.uptimeMillis()-startTime) + "ms.");
360 }
361 mResources.finishPreloading();
362 } catch (RuntimeException e) {
363 Log.w(TAG, "Failure preloading resources", e);
364 } finally {
365 Debug.stopAllocCounting();
366 }
367 }
368
369 private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) {
370 int N = ar.length();
371 for (int i=0; i<N; i++) {
372 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700373 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
375 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700376 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 runtime.runFinalizationSync();
378 Debug.resetGlobalAllocSize();
379 }
380 int id = ar.getResourceId(i, 0);
Joe Onorato43a17652011-04-06 19:22:23 -0700381 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
383 }
384 if (id != 0) {
Dianne Hackborndde331c2012-08-03 14:01:57 -0700385 if (mResources.getColorStateList(id) == null) {
386 throw new IllegalArgumentException(
387 "Unable to find preloaded color resource #0x"
388 + Integer.toHexString(id)
389 + " (" + ar.getString(i) + ")");
390 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 }
392 }
393 return N;
394 }
395
396
397 private static int preloadDrawables(VMRuntime runtime, TypedArray ar) {
398 int N = ar.length();
399 for (int i=0; i<N; i++) {
400 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700401 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
403 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700404 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405 runtime.runFinalizationSync();
406 Debug.resetGlobalAllocSize();
407 }
408 int id = ar.getResourceId(i, 0);
Joe Onorato43a17652011-04-06 19:22:23 -0700409 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
411 }
412 if (id != 0) {
Dianne Hackborndde331c2012-08-03 14:01:57 -0700413 if (mResources.getDrawable(id) == null) {
414 throw new IllegalArgumentException(
415 "Unable to find preloaded drawable resource #0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 + Integer.toHexString(id)
Dianne Hackborndde331c2012-08-03 14:01:57 -0700417 + " (" + ar.getString(i) + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 }
419 }
420 }
421 return N;
422 }
423
424 /**
425 * Runs several special GCs to try to clean up a few generations of
426 * softly- and final-reachable objects, along with any other garbage.
427 * This is only useful just before a fork().
428 */
429 /*package*/ static void gc() {
430 final VMRuntime runtime = VMRuntime.getRuntime();
431
432 /* runFinalizationSync() lets finalizers be called in Zygote,
433 * which doesn't have a HeapWorker thread.
434 */
Brian Carlstrom08065b92011-04-01 15:49:41 -0700435 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 runtime.runFinalizationSync();
Brian Carlstrom08065b92011-04-01 15:49:41 -0700437 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 runtime.runFinalizationSync();
Brian Carlstrom08065b92011-04-01 15:49:41 -0700439 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 runtime.runFinalizationSync();
441 }
442
443 /**
444 * Finish remaining work for the newly forked system server process.
445 */
446 private static void handleSystemServerProcess(
447 ZygoteConnection.Arguments parsedArgs)
448 throws ZygoteInit.MethodAndArgsCaller {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449
450 closeServerSocket();
451
Mike Lockwood90960e82010-08-06 09:15:25 -0400452 // set umask to 0077 so new files and directories will default to owner-only permissions.
Kenny Root4c74f8c2012-08-17 08:45:55 -0700453 Libcore.os.umask(S_IRWXG | S_IRWXO);
Mike Lockwood90960e82010-08-06 09:15:25 -0400454
Jeff Brownebed7d62011-05-16 17:08:42 -0700455 if (parsedArgs.niceName != null) {
456 Process.setArgV0(parsedArgs.niceName);
457 }
458
459 if (parsedArgs.invokeWith != null) {
460 WrapperInit.execApplication(parsedArgs.invokeWith,
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700461 parsedArgs.niceName, parsedArgs.targetSdkVersion,
462 null, parsedArgs.remainingArgs);
Jeff Brownebed7d62011-05-16 17:08:42 -0700463 } else {
464 /*
465 * Pass the remaining arguments to SystemServer.
466 */
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700467 RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
Jeff Brownebed7d62011-05-16 17:08:42 -0700468 }
469
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470 /* should never reach here */
471 }
472
473 /**
474 * Prepare the arguments and fork for the system server process.
475 */
Bob Leee5408332009-09-04 18:31:17 -0700476 private static boolean startSystemServer()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477 throws MethodAndArgsCaller, RuntimeException {
Alex Klyubin48a06e72013-04-19 10:01:42 -0700478 long capabilities = posixCapabilitiesAsBits(
479 OsConstants.CAP_KILL,
480 OsConstants.CAP_NET_ADMIN,
481 OsConstants.CAP_NET_BIND_SERVICE,
482 OsConstants.CAP_NET_BROADCAST,
483 OsConstants.CAP_NET_RAW,
484 OsConstants.CAP_SYS_BOOT,
485 OsConstants.CAP_SYS_MODULE,
486 OsConstants.CAP_SYS_NICE,
487 OsConstants.CAP_SYS_RESOURCE,
488 OsConstants.CAP_SYS_TIME,
489 OsConstants.CAP_SYS_TTY_CONFIG
490 );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 /* Hardcoded command line to start the system server */
492 String args[] = {
493 "--setuid=1000",
494 "--setgid=1000",
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700495 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003,3006,3007",
Alex Klyubin48a06e72013-04-19 10:01:42 -0700496 "--capabilities=" + capabilities + "," + capabilities,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 "--runtime-init",
498 "--nice-name=system_server",
499 "com.android.server.SystemServer",
500 };
501 ZygoteConnection.Arguments parsedArgs = null;
502
503 int pid;
504
505 try {
506 parsedArgs = new ZygoteConnection.Arguments(args);
Jeff Brownebed7d62011-05-16 17:08:42 -0700507 ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
508 ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509
510 /* Request to fork the system server process */
511 pid = Zygote.forkSystemServer(
512 parsedArgs.uid, parsedArgs.gid,
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700513 parsedArgs.gids,
514 parsedArgs.debugFlags,
515 null,
Andy McFadden1b4c7962010-10-27 11:26:05 -0700516 parsedArgs.permittedCapabilities,
517 parsedArgs.effectiveCapabilities);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 } catch (IllegalArgumentException ex) {
519 throw new RuntimeException(ex);
Bob Leee5408332009-09-04 18:31:17 -0700520 }
521
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 /* For child process */
523 if (pid == 0) {
524 handleSystemServerProcess(parsedArgs);
525 }
526
527 return true;
528 }
529
Alex Klyubin48a06e72013-04-19 10:01:42 -0700530 /**
531 * Gets the bit array representation of the provided list of POSIX capabilities.
532 */
533 private static long posixCapabilitiesAsBits(int... capabilities) {
534 long result = 0;
535 for (int capability : capabilities) {
536 if ((capability < 0) || (capability > OsConstants.CAP_LAST_CAP)) {
537 throw new IllegalArgumentException(String.valueOf(capability));
538 }
539 result |= (1L << capability);
540 }
541 return result;
542 }
543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 public static void main(String argv[]) {
545 try {
Bob Leee5408332009-09-04 18:31:17 -0700546 // Start profiling the zygote initialization.
547 SamplingProfilerIntegration.start();
548
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 registerZygoteSocket();
550 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
551 SystemClock.uptimeMillis());
Jeff Brown0c2313d2011-06-10 22:46:40 -0700552 preload();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
554 SystemClock.uptimeMillis());
555
Brian Carlstrom17510862010-08-18 14:27:40 -0700556 // Finish profiling the zygote initialization.
557 SamplingProfilerIntegration.writeZygoteSnapshot();
Bob Leee5408332009-09-04 18:31:17 -0700558
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559 // Do an initial gc to clean up after startup
560 gc();
561
Jamie Gennis6ad04522013-04-15 18:53:24 -0700562 // Disable tracing so that forked processes do not inherit stale tracing tags from
563 // Zygote.
564 Trace.setTracingEnabled(false);
565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 // If requested, start system server directly from Zygote
567 if (argv.length != 2) {
Barry Hayes0b3533a2010-01-20 12:46:47 -0800568 throw new RuntimeException(argv[0] + USAGE_STRING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 }
570
Jeff Brownebed7d62011-05-16 17:08:42 -0700571 if (argv[1].equals("start-system-server")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 startSystemServer();
Jeff Brownebed7d62011-05-16 17:08:42 -0700573 } else if (!argv[1].equals("")) {
Barry Hayes0b3533a2010-01-20 12:46:47 -0800574 throw new RuntimeException(argv[0] + USAGE_STRING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 }
576
577 Log.i(TAG, "Accepting command socket connections");
578
Nick Kralevichcae3d9f2013-01-30 09:51:40 -0800579 runSelectLoop();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580
581 closeServerSocket();
582 } catch (MethodAndArgsCaller caller) {
583 caller.run();
584 } catch (RuntimeException ex) {
585 Log.e(TAG, "Zygote died with exception", ex);
586 closeServerSocket();
587 throw ex;
588 }
589 }
590
591 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 * Runs the zygote process's select loop. Accepts new connections as
593 * they happen, and reads commands from connections one spawn-request's
594 * worth at a time.
595 *
596 * @throws MethodAndArgsCaller in a child process when a main() should
597 * be executed.
598 */
Nick Kralevichcae3d9f2013-01-30 09:51:40 -0800599 private static void runSelectLoop() throws MethodAndArgsCaller {
600 ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
601 ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 FileDescriptor[] fdArray = new FileDescriptor[4];
603
604 fds.add(sServerSocket.getFileDescriptor());
605 peers.add(null);
606
607 int loopCount = GC_LOOP_COUNT;
608 while (true) {
609 int index;
610
611 /*
612 * Call gc() before we block in select().
613 * It's work that has to be done anyway, and it's better
614 * to avoid making every child do it. It will also
615 * madvise() any free memory as a side-effect.
616 *
617 * Don't call it every time, because walking the entire
618 * heap is a lot of overhead to free a few hundred bytes.
619 */
620 if (loopCount <= 0) {
621 gc();
622 loopCount = GC_LOOP_COUNT;
623 } else {
624 loopCount--;
625 }
626
627
628 try {
629 fdArray = fds.toArray(fdArray);
630 index = selectReadable(fdArray);
631 } catch (IOException ex) {
632 throw new RuntimeException("Error in select()", ex);
633 }
634
635 if (index < 0) {
636 throw new RuntimeException("Error in select()");
637 } else if (index == 0) {
638 ZygoteConnection newPeer = acceptCommandPeer();
639 peers.add(newPeer);
640 fds.add(newPeer.getFileDesciptor());
641 } else {
642 boolean done;
643 done = peers.get(index).runOnce();
644
645 if (done) {
646 peers.remove(index);
647 fds.remove(index);
648 }
649 }
650 }
651 }
652
653 /**
654 * The Linux syscall "setreuid()"
655 * @param ruid real uid
656 * @param euid effective uid
657 * @return 0 on success, non-zero errno on fail
658 */
659 static native int setreuid(int ruid, int euid);
660
661 /**
662 * The Linux syscall "setregid()"
663 * @param rgid real gid
664 * @param egid effective gid
665 * @return 0 on success, non-zero errno on fail
666 */
667 static native int setregid(int rgid, int egid);
668
669 /**
670 * Invokes the linux syscall "setpgid"
671 *
672 * @param pid pid to change
673 * @param pgid new process group of pid
674 * @return 0 on success or non-zero errno on fail
675 */
676 static native int setpgid(int pid, int pgid);
677
678 /**
679 * Invokes the linux syscall "getpgid"
680 *
681 * @param pid pid to query
682 * @return pgid of pid in question
683 * @throws IOException on error
684 */
685 static native int getpgid(int pid) throws IOException;
686
687 /**
688 * Invokes the syscall dup2() to copy the specified descriptors into
689 * stdin, stdout, and stderr. The existing stdio descriptors will be
690 * closed and errors during close will be ignored. The specified
691 * descriptors will also remain open at their original descriptor numbers,
692 * so the caller may want to close the original descriptors.
693 *
694 * @param in new stdin
695 * @param out new stdout
696 * @param err new stderr
697 * @throws IOException
698 */
699 static native void reopenStdio(FileDescriptor in,
700 FileDescriptor out, FileDescriptor err) throws IOException;
701
702 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 * Toggles the close-on-exec flag for the specified file descriptor.
704 *
705 * @param fd non-null; file descriptor
706 * @param flag desired close-on-exec flag state
707 * @throws IOException
708 */
709 static native void setCloseOnExec(FileDescriptor fd, boolean flag)
710 throws IOException;
711
712 /**
713 * Retrieves the permitted capability set from another process.
714 *
715 * @param pid &gt;=0 process ID or 0 for this process
716 * @throws IOException on error
717 */
718 static native long capgetPermitted(int pid)
719 throws IOException;
720
721 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800722 * Invokes select() on the provider array of file descriptors (selecting
723 * for readability only). Array elements of null are ignored.
724 *
725 * @param fds non-null; array of readable file descriptors
726 * @return index of descriptor that is now readable or -1 for empty array.
727 * @throws IOException if an error occurs
728 */
729 static native int selectReadable(FileDescriptor[] fds) throws IOException;
730
731 /**
732 * Creates a file descriptor from an int fd.
733 *
734 * @param fd integer OS file descriptor
735 * @return non-null; FileDescriptor instance
736 * @throws IOException if fd is invalid
737 */
738 static native FileDescriptor createFileDescriptor(int fd)
739 throws IOException;
740
741 /**
742 * Class not instantiable.
743 */
744 private ZygoteInit() {
745 }
746
747 /**
748 * Helper exception class which holds a method and arguments and
749 * can call them. This is used as part of a trampoline to get rid of
750 * the initial process setup stack frames.
751 */
752 public static class MethodAndArgsCaller extends Exception
753 implements Runnable {
754 /** method to call */
755 private final Method mMethod;
756
757 /** argument array */
758 private final String[] mArgs;
759
760 public MethodAndArgsCaller(Method method, String[] args) {
761 mMethod = method;
762 mArgs = args;
763 }
764
765 public void run() {
766 try {
767 mMethod.invoke(null, new Object[] { mArgs });
768 } catch (IllegalAccessException ex) {
769 throw new RuntimeException(ex);
770 } catch (InvocationTargetException ex) {
771 Throwable cause = ex.getCause();
772 if (cause instanceof RuntimeException) {
773 throw (RuntimeException) cause;
774 } else if (cause instanceof Error) {
775 throw (Error) cause;
776 }
777 throw new RuntimeException(ex);
778 }
779 }
780 }
781}