blob: fb22df7e4850ff6b5ae075993830faacba0031e5 [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);
Bob Lee2e93f652009-08-11 01:16:03 -0700294 } catch (Throwable t) {
295 Log.e(TAG, "Error preloading " + line + ".", t);
296 if (t instanceof Error) {
297 throw (Error) t;
298 }
299 if (t instanceof RuntimeException) {
300 throw (RuntimeException) t;
301 }
302 throw new RuntimeException(t);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303 }
304 }
305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 Log.i(TAG, "...preloaded " + count + " classes in "
307 + (SystemClock.uptimeMillis()-startTime) + "ms.");
308 } catch (IOException e) {
309 Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
310 } finally {
Brian Carlstrom46703b02011-04-06 15:41:29 -0700311 IoUtils.closeQuietly(is);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312 // Restore default.
313 runtime.setTargetHeapUtilization(defaultUtilization);
314
315 Debug.stopAllocCounting();
316
317 // Bring back root. We'll need it later.
318 setEffectiveUser(ROOT_UID);
319 setEffectiveGroup(ROOT_GID);
320 }
321 }
322 }
323
324 /**
325 * Load in commonly used resources, so they can be shared across
326 * processes.
327 *
328 * These tend to be a few Kbytes, but are frequently in the 20-40K
329 * range, and occasionally even larger.
330 */
331 private static void preloadResources() {
332 final VMRuntime runtime = VMRuntime.getRuntime();
Bob Leee5408332009-09-04 18:31:17 -0700333
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 Debug.startAllocCounting();
335 try {
Brian Carlstrom08065b92011-04-01 15:49:41 -0700336 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 runtime.runFinalizationSync();
338 mResources = Resources.getSystem();
339 mResources.startPreloading();
340 if (PRELOAD_RESOURCES) {
341 Log.i(TAG, "Preloading resources...");
342
343 long startTime = SystemClock.uptimeMillis();
344 TypedArray ar = mResources.obtainTypedArray(
345 com.android.internal.R.array.preloaded_drawables);
346 int N = preloadDrawables(runtime, ar);
Jeff Brown14577c42012-03-08 16:40:14 -0800347 ar.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 Log.i(TAG, "...preloaded " + N + " resources in "
349 + (SystemClock.uptimeMillis()-startTime) + "ms.");
350
351 startTime = SystemClock.uptimeMillis();
352 ar = mResources.obtainTypedArray(
353 com.android.internal.R.array.preloaded_color_state_lists);
354 N = preloadColorStateLists(runtime, ar);
Jeff Brown14577c42012-03-08 16:40:14 -0800355 ar.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 Log.i(TAG, "...preloaded " + N + " resources in "
357 + (SystemClock.uptimeMillis()-startTime) + "ms.");
358 }
359 mResources.finishPreloading();
360 } catch (RuntimeException e) {
361 Log.w(TAG, "Failure preloading resources", e);
362 } finally {
363 Debug.stopAllocCounting();
364 }
365 }
366
367 private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) {
368 int N = ar.length();
369 for (int i=0; i<N; i++) {
370 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700371 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
373 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700374 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 runtime.runFinalizationSync();
376 Debug.resetGlobalAllocSize();
377 }
378 int id = ar.getResourceId(i, 0);
Joe Onorato43a17652011-04-06 19:22:23 -0700379 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
381 }
382 if (id != 0) {
Dianne Hackborndde331c2012-08-03 14:01:57 -0700383 if (mResources.getColorStateList(id) == null) {
384 throw new IllegalArgumentException(
385 "Unable to find preloaded color resource #0x"
386 + Integer.toHexString(id)
387 + " (" + ar.getString(i) + ")");
388 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 }
390 }
391 return N;
392 }
393
394
395 private static int preloadDrawables(VMRuntime runtime, TypedArray ar) {
396 int N = ar.length();
397 for (int i=0; i<N; i++) {
398 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700399 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
401 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700402 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 runtime.runFinalizationSync();
404 Debug.resetGlobalAllocSize();
405 }
406 int id = ar.getResourceId(i, 0);
Joe Onorato43a17652011-04-06 19:22:23 -0700407 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
409 }
410 if (id != 0) {
Dianne Hackborndde331c2012-08-03 14:01:57 -0700411 if (mResources.getDrawable(id) == null) {
412 throw new IllegalArgumentException(
413 "Unable to find preloaded drawable resource #0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 + Integer.toHexString(id)
Dianne Hackborndde331c2012-08-03 14:01:57 -0700415 + " (" + ar.getString(i) + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 }
417 }
418 }
419 return N;
420 }
421
422 /**
423 * Runs several special GCs to try to clean up a few generations of
424 * softly- and final-reachable objects, along with any other garbage.
425 * This is only useful just before a fork().
426 */
427 /*package*/ static void gc() {
428 final VMRuntime runtime = VMRuntime.getRuntime();
429
430 /* runFinalizationSync() lets finalizers be called in Zygote,
431 * which doesn't have a HeapWorker thread.
432 */
Brian Carlstrom08065b92011-04-01 15:49:41 -0700433 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 runtime.runFinalizationSync();
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();
439 }
440
441 /**
442 * Finish remaining work for the newly forked system server process.
443 */
444 private static void handleSystemServerProcess(
445 ZygoteConnection.Arguments parsedArgs)
446 throws ZygoteInit.MethodAndArgsCaller {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447
448 closeServerSocket();
449
Mike Lockwood90960e82010-08-06 09:15:25 -0400450 // set umask to 0077 so new files and directories will default to owner-only permissions.
Kenny Root4c74f8c2012-08-17 08:45:55 -0700451 Libcore.os.umask(S_IRWXG | S_IRWXO);
Mike Lockwood90960e82010-08-06 09:15:25 -0400452
Jeff Brownebed7d62011-05-16 17:08:42 -0700453 if (parsedArgs.niceName != null) {
454 Process.setArgV0(parsedArgs.niceName);
455 }
456
457 if (parsedArgs.invokeWith != null) {
458 WrapperInit.execApplication(parsedArgs.invokeWith,
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700459 parsedArgs.niceName, parsedArgs.targetSdkVersion,
460 null, parsedArgs.remainingArgs);
Jeff Brownebed7d62011-05-16 17:08:42 -0700461 } else {
462 /*
463 * Pass the remaining arguments to SystemServer.
464 */
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700465 RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
Jeff Brownebed7d62011-05-16 17:08:42 -0700466 }
467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 /* should never reach here */
469 }
470
471 /**
472 * Prepare the arguments and fork for the system server process.
473 */
Bob Leee5408332009-09-04 18:31:17 -0700474 private static boolean startSystemServer()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 throws MethodAndArgsCaller, RuntimeException {
Alex Klyubin48a06e72013-04-19 10:01:42 -0700476 long capabilities = posixCapabilitiesAsBits(
477 OsConstants.CAP_KILL,
478 OsConstants.CAP_NET_ADMIN,
479 OsConstants.CAP_NET_BIND_SERVICE,
480 OsConstants.CAP_NET_BROADCAST,
481 OsConstants.CAP_NET_RAW,
482 OsConstants.CAP_SYS_BOOT,
483 OsConstants.CAP_SYS_MODULE,
484 OsConstants.CAP_SYS_NICE,
485 OsConstants.CAP_SYS_RESOURCE,
486 OsConstants.CAP_SYS_TIME,
487 OsConstants.CAP_SYS_TTY_CONFIG
488 );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 /* Hardcoded command line to start the system server */
490 String args[] = {
491 "--setuid=1000",
492 "--setgid=1000",
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700493 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003,3006,3007",
Alex Klyubin48a06e72013-04-19 10:01:42 -0700494 "--capabilities=" + capabilities + "," + capabilities,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 "--runtime-init",
496 "--nice-name=system_server",
497 "com.android.server.SystemServer",
498 };
499 ZygoteConnection.Arguments parsedArgs = null;
500
501 int pid;
502
503 try {
504 parsedArgs = new ZygoteConnection.Arguments(args);
Jeff Brownebed7d62011-05-16 17:08:42 -0700505 ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
506 ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507
508 /* Request to fork the system server process */
509 pid = Zygote.forkSystemServer(
510 parsedArgs.uid, parsedArgs.gid,
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700511 parsedArgs.gids,
512 parsedArgs.debugFlags,
513 null,
Andy McFadden1b4c7962010-10-27 11:26:05 -0700514 parsedArgs.permittedCapabilities,
515 parsedArgs.effectiveCapabilities);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 } catch (IllegalArgumentException ex) {
517 throw new RuntimeException(ex);
Bob Leee5408332009-09-04 18:31:17 -0700518 }
519
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 /* For child process */
521 if (pid == 0) {
522 handleSystemServerProcess(parsedArgs);
523 }
524
525 return true;
526 }
527
Alex Klyubin48a06e72013-04-19 10:01:42 -0700528 /**
529 * Gets the bit array representation of the provided list of POSIX capabilities.
530 */
531 private static long posixCapabilitiesAsBits(int... capabilities) {
532 long result = 0;
533 for (int capability : capabilities) {
534 if ((capability < 0) || (capability > OsConstants.CAP_LAST_CAP)) {
535 throw new IllegalArgumentException(String.valueOf(capability));
536 }
537 result |= (1L << capability);
538 }
539 return result;
540 }
541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 public static void main(String argv[]) {
543 try {
Bob Leee5408332009-09-04 18:31:17 -0700544 // Start profiling the zygote initialization.
545 SamplingProfilerIntegration.start();
546
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 registerZygoteSocket();
548 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
549 SystemClock.uptimeMillis());
Jeff Brown0c2313d2011-06-10 22:46:40 -0700550 preload();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
552 SystemClock.uptimeMillis());
553
Brian Carlstrom17510862010-08-18 14:27:40 -0700554 // Finish profiling the zygote initialization.
555 SamplingProfilerIntegration.writeZygoteSnapshot();
Bob Leee5408332009-09-04 18:31:17 -0700556
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 // Do an initial gc to clean up after startup
558 gc();
559
Jamie Gennis6ad04522013-04-15 18:53:24 -0700560 // Disable tracing so that forked processes do not inherit stale tracing tags from
561 // Zygote.
562 Trace.setTracingEnabled(false);
563
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 // If requested, start system server directly from Zygote
565 if (argv.length != 2) {
Barry Hayes0b3533a2010-01-20 12:46:47 -0800566 throw new RuntimeException(argv[0] + USAGE_STRING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 }
568
Jeff Brownebed7d62011-05-16 17:08:42 -0700569 if (argv[1].equals("start-system-server")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570 startSystemServer();
Jeff Brownebed7d62011-05-16 17:08:42 -0700571 } else if (!argv[1].equals("")) {
Barry Hayes0b3533a2010-01-20 12:46:47 -0800572 throw new RuntimeException(argv[0] + USAGE_STRING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 }
574
575 Log.i(TAG, "Accepting command socket connections");
576
Nick Kralevichcae3d9f2013-01-30 09:51:40 -0800577 runSelectLoop();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578
579 closeServerSocket();
580 } catch (MethodAndArgsCaller caller) {
581 caller.run();
582 } catch (RuntimeException ex) {
583 Log.e(TAG, "Zygote died with exception", ex);
584 closeServerSocket();
585 throw ex;
586 }
587 }
588
589 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 * Runs the zygote process's select loop. Accepts new connections as
591 * they happen, and reads commands from connections one spawn-request's
592 * worth at a time.
593 *
594 * @throws MethodAndArgsCaller in a child process when a main() should
595 * be executed.
596 */
Nick Kralevichcae3d9f2013-01-30 09:51:40 -0800597 private static void runSelectLoop() throws MethodAndArgsCaller {
598 ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
599 ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 FileDescriptor[] fdArray = new FileDescriptor[4];
601
602 fds.add(sServerSocket.getFileDescriptor());
603 peers.add(null);
604
605 int loopCount = GC_LOOP_COUNT;
606 while (true) {
607 int index;
608
609 /*
610 * Call gc() before we block in select().
611 * It's work that has to be done anyway, and it's better
612 * to avoid making every child do it. It will also
613 * madvise() any free memory as a side-effect.
614 *
615 * Don't call it every time, because walking the entire
616 * heap is a lot of overhead to free a few hundred bytes.
617 */
618 if (loopCount <= 0) {
619 gc();
620 loopCount = GC_LOOP_COUNT;
621 } else {
622 loopCount--;
623 }
624
625
626 try {
627 fdArray = fds.toArray(fdArray);
628 index = selectReadable(fdArray);
629 } catch (IOException ex) {
630 throw new RuntimeException("Error in select()", ex);
631 }
632
633 if (index < 0) {
634 throw new RuntimeException("Error in select()");
635 } else if (index == 0) {
636 ZygoteConnection newPeer = acceptCommandPeer();
637 peers.add(newPeer);
638 fds.add(newPeer.getFileDesciptor());
639 } else {
640 boolean done;
641 done = peers.get(index).runOnce();
642
643 if (done) {
644 peers.remove(index);
645 fds.remove(index);
646 }
647 }
648 }
649 }
650
651 /**
652 * The Linux syscall "setreuid()"
653 * @param ruid real uid
654 * @param euid effective uid
655 * @return 0 on success, non-zero errno on fail
656 */
657 static native int setreuid(int ruid, int euid);
658
659 /**
660 * The Linux syscall "setregid()"
661 * @param rgid real gid
662 * @param egid effective gid
663 * @return 0 on success, non-zero errno on fail
664 */
665 static native int setregid(int rgid, int egid);
666
667 /**
668 * Invokes the linux syscall "setpgid"
669 *
670 * @param pid pid to change
671 * @param pgid new process group of pid
672 * @return 0 on success or non-zero errno on fail
673 */
674 static native int setpgid(int pid, int pgid);
675
676 /**
677 * Invokes the linux syscall "getpgid"
678 *
679 * @param pid pid to query
680 * @return pgid of pid in question
681 * @throws IOException on error
682 */
683 static native int getpgid(int pid) throws IOException;
684
685 /**
686 * Invokes the syscall dup2() to copy the specified descriptors into
687 * stdin, stdout, and stderr. The existing stdio descriptors will be
688 * closed and errors during close will be ignored. The specified
689 * descriptors will also remain open at their original descriptor numbers,
690 * so the caller may want to close the original descriptors.
691 *
692 * @param in new stdin
693 * @param out new stdout
694 * @param err new stderr
695 * @throws IOException
696 */
697 static native void reopenStdio(FileDescriptor in,
698 FileDescriptor out, FileDescriptor err) throws IOException;
699
700 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 * Toggles the close-on-exec flag for the specified file descriptor.
702 *
703 * @param fd non-null; file descriptor
704 * @param flag desired close-on-exec flag state
705 * @throws IOException
706 */
707 static native void setCloseOnExec(FileDescriptor fd, boolean flag)
708 throws IOException;
709
710 /**
711 * Retrieves the permitted capability set from another process.
712 *
713 * @param pid &gt;=0 process ID or 0 for this process
714 * @throws IOException on error
715 */
716 static native long capgetPermitted(int pid)
717 throws IOException;
718
719 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 * Invokes select() on the provider array of file descriptors (selecting
721 * for readability only). Array elements of null are ignored.
722 *
723 * @param fds non-null; array of readable file descriptors
724 * @return index of descriptor that is now readable or -1 for empty array.
725 * @throws IOException if an error occurs
726 */
727 static native int selectReadable(FileDescriptor[] fds) throws IOException;
728
729 /**
730 * Creates a file descriptor from an int fd.
731 *
732 * @param fd integer OS file descriptor
733 * @return non-null; FileDescriptor instance
734 * @throws IOException if fd is invalid
735 */
736 static native FileDescriptor createFileDescriptor(int fd)
737 throws IOException;
738
739 /**
740 * Class not instantiable.
741 */
742 private ZygoteInit() {
743 }
744
745 /**
746 * Helper exception class which holds a method and arguments and
747 * can call them. This is used as part of a trampoline to get rid of
748 * the initial process setup stack frames.
749 */
750 public static class MethodAndArgsCaller extends Exception
751 implements Runnable {
752 /** method to call */
753 private final Method mMethod;
754
755 /** argument array */
756 private final String[] mArgs;
757
758 public MethodAndArgsCaller(Method method, String[] args) {
759 mMethod = method;
760 mArgs = args;
761 }
762
763 public void run() {
764 try {
765 mMethod.invoke(null, new Object[] { mArgs });
766 } catch (IllegalAccessException ex) {
767 throw new RuntimeException(ex);
768 } catch (InvocationTargetException ex) {
769 Throwable cause = ex.getCause();
770 if (cause instanceof RuntimeException) {
771 throw (RuntimeException) cause;
772 } else if (cause instanceof Error) {
773 throw (Error) cause;
774 }
775 throw new RuntimeException(ex);
776 }
777 }
778 }
779}