blob: ccc0089cb0c0d559b50a01e5294a812ec37ffc31 [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;
Romain Guy74c69122013-05-08 17:54:20 -070025import android.opengl.EGL14;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.os.Debug;
Jeff Brownebed7d62011-05-16 17:08:42 -070027import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.os.SystemClock;
Romain Guyc5e36382013-05-09 11:08:17 -070029import android.os.SystemProperties;
Jamie Gennis6ad04522013-04-15 18:53:24 -070030import android.os.Trace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.util.EventLog;
32import android.util.Log;
33
34import dalvik.system.VMRuntime;
35import dalvik.system.Zygote;
36
Brian Carlstrom46703b02011-04-06 15:41:29 -070037import libcore.io.IoUtils;
Kenny Root4c74f8c2012-08-17 08:45:55 -070038import libcore.io.Libcore;
Alex Klyubin48a06e72013-04-19 10:01:42 -070039import libcore.io.OsConstants;
Brian Carlstrom46703b02011-04-06 15:41:29 -070040
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import java.io.BufferedReader;
42import java.io.FileDescriptor;
43import java.io.IOException;
44import java.io.InputStream;
45import java.io.InputStreamReader;
46import java.lang.reflect.InvocationTargetException;
47import java.lang.reflect.Method;
48import java.lang.reflect.Modifier;
49import java.util.ArrayList;
50
51/**
52 * Startup class for the zygote process.
53 *
54 * Pre-initializes some classes, and then waits for commands on a UNIX domain
Elliott Hughese1dfcb72011-07-08 11:08:07 -070055 * socket. Based on these commands, forks off child processes that inherit
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056 * the initial state of the VM.
57 *
58 * Please see {@link ZygoteConnection.Arguments} for documentation on the
59 * client protocol.
60 *
61 * @hide
62 */
63public class ZygoteInit {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064 private static final String TAG = "Zygote";
65
Romain Guyc5e36382013-05-09 11:08:17 -070066 private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
67
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068 private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";
69
70 private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
71 private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
72
73 /** when preloading, GC after allocating this many bytes */
74 private static final int PRELOAD_GC_THRESHOLD = 50000;
75
Barry Hayes0b3533a2010-01-20 12:46:47 -080076 public static final String USAGE_STRING =
Jeff Brownebed7d62011-05-16 17:08:42 -070077 " <\"start-system-server\"|\"\" for startSystemServer>";
Barry Hayes0b3533a2010-01-20 12:46:47 -080078
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 private static LocalServerSocket sServerSocket;
80
81 /**
82 * Used to pre-load resources. We hold a global reference on it so it
83 * never gets destroyed.
84 */
85 private static Resources mResources;
Bob Leee5408332009-09-04 18:31:17 -070086
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 /**
88 * The number of times that the main Zygote loop
89 * should run before calling gc() again.
90 */
91 static final int GC_LOOP_COUNT = 10;
92
93 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 * 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
Jeff Brown0c2313d2011-06-10 22:46:40 -0700230 static void preload() {
231 preloadClasses();
232 preloadResources();
Romain Guy74c69122013-05-08 17:54:20 -0700233 preloadOpenGL();
234 }
235
236 private static void preloadOpenGL() {
Romain Guyc5e36382013-05-09 11:08:17 -0700237 if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false)) {
238 EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
239 }
Jeff Brown0c2313d2011-06-10 22:46:40 -0700240 }
241
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 /**
243 * Performs Zygote process initialization. Loads and initializes
244 * commonly used classes.
245 *
246 * Most classes only cause a few hundred bytes to be allocated, but
247 * a few will allocate a dozen Kbytes (in one case, 500+K).
248 */
249 private static void preloadClasses() {
250 final VMRuntime runtime = VMRuntime.getRuntime();
Bob Leee5408332009-09-04 18:31:17 -0700251
Andy McFaddendc7bf5d2012-01-23 09:48:53 -0800252 InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 PRELOADED_CLASSES);
254 if (is == null) {
255 Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
256 } else {
257 Log.i(TAG, "Preloading classes...");
258 long startTime = SystemClock.uptimeMillis();
Bob Leee5408332009-09-04 18:31:17 -0700259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 // Drop root perms while running static initializers.
261 setEffectiveGroup(UNPRIVILEGED_GID);
262 setEffectiveUser(UNPRIVILEGED_UID);
263
264 // Alter the target heap utilization. With explicit GCs this
265 // is not likely to have any effect.
266 float defaultUtilization = runtime.getTargetHeapUtilization();
267 runtime.setTargetHeapUtilization(0.8f);
268
269 // Start with a clean slate.
Brian Carlstrom08065b92011-04-01 15:49:41 -0700270 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271 runtime.runFinalizationSync();
272 Debug.startAllocCounting();
273
274 try {
Bob Leee5408332009-09-04 18:31:17 -0700275 BufferedReader br
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 = new BufferedReader(new InputStreamReader(is), 256);
277
278 int count = 0;
279 String line;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 while ((line = br.readLine()) != null) {
281 // Skip comments and blank lines.
282 line = line.trim();
283 if (line.startsWith("#") || line.equals("")) {
284 continue;
285 }
286
287 try {
Joe Onorato43a17652011-04-06 19:22:23 -0700288 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 Log.v(TAG, "Preloading " + line + "...");
290 }
291 Class.forName(line);
292 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700293 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 Log.v(TAG,
295 " GC at " + Debug.getGlobalAllocSize());
296 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700297 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 runtime.runFinalizationSync();
299 Debug.resetGlobalAllocSize();
300 }
301 count++;
302 } catch (ClassNotFoundException e) {
Jesse Wilsone2417542010-06-03 12:33:26 -0700303 Log.w(TAG, "Class not found for preloading: " + line);
Bob Lee2e93f652009-08-11 01:16:03 -0700304 } catch (Throwable t) {
305 Log.e(TAG, "Error preloading " + line + ".", t);
306 if (t instanceof Error) {
307 throw (Error) t;
308 }
309 if (t instanceof RuntimeException) {
310 throw (RuntimeException) t;
311 }
312 throw new RuntimeException(t);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 }
314 }
315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 Log.i(TAG, "...preloaded " + count + " classes in "
317 + (SystemClock.uptimeMillis()-startTime) + "ms.");
318 } catch (IOException e) {
319 Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
320 } finally {
Brian Carlstrom46703b02011-04-06 15:41:29 -0700321 IoUtils.closeQuietly(is);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 // Restore default.
323 runtime.setTargetHeapUtilization(defaultUtilization);
324
325 Debug.stopAllocCounting();
326
327 // Bring back root. We'll need it later.
328 setEffectiveUser(ROOT_UID);
329 setEffectiveGroup(ROOT_GID);
330 }
331 }
332 }
333
334 /**
335 * Load in commonly used resources, so they can be shared across
336 * processes.
337 *
338 * These tend to be a few Kbytes, but are frequently in the 20-40K
339 * range, and occasionally even larger.
340 */
341 private static void preloadResources() {
342 final VMRuntime runtime = VMRuntime.getRuntime();
Bob Leee5408332009-09-04 18:31:17 -0700343
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 Debug.startAllocCounting();
345 try {
Brian Carlstrom08065b92011-04-01 15:49:41 -0700346 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 runtime.runFinalizationSync();
348 mResources = Resources.getSystem();
349 mResources.startPreloading();
350 if (PRELOAD_RESOURCES) {
351 Log.i(TAG, "Preloading resources...");
352
353 long startTime = SystemClock.uptimeMillis();
354 TypedArray ar = mResources.obtainTypedArray(
355 com.android.internal.R.array.preloaded_drawables);
356 int N = preloadDrawables(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 startTime = SystemClock.uptimeMillis();
362 ar = mResources.obtainTypedArray(
363 com.android.internal.R.array.preloaded_color_state_lists);
364 N = preloadColorStateLists(runtime, ar);
Jeff Brown14577c42012-03-08 16:40:14 -0800365 ar.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 Log.i(TAG, "...preloaded " + N + " resources in "
367 + (SystemClock.uptimeMillis()-startTime) + "ms.");
368 }
369 mResources.finishPreloading();
370 } catch (RuntimeException e) {
371 Log.w(TAG, "Failure preloading resources", e);
372 } finally {
373 Debug.stopAllocCounting();
374 }
375 }
376
377 private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) {
378 int N = ar.length();
379 for (int i=0; i<N; i++) {
380 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700381 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
383 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700384 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 runtime.runFinalizationSync();
386 Debug.resetGlobalAllocSize();
387 }
388 int id = ar.getResourceId(i, 0);
Joe Onorato43a17652011-04-06 19:22:23 -0700389 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
391 }
392 if (id != 0) {
Dianne Hackborndde331c2012-08-03 14:01:57 -0700393 if (mResources.getColorStateList(id) == null) {
394 throw new IllegalArgumentException(
395 "Unable to find preloaded color resource #0x"
396 + Integer.toHexString(id)
397 + " (" + ar.getString(i) + ")");
398 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 }
400 }
401 return N;
402 }
403
404
405 private static int preloadDrawables(VMRuntime runtime, TypedArray ar) {
406 int N = ar.length();
407 for (int i=0; i<N; i++) {
408 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700409 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
411 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700412 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 runtime.runFinalizationSync();
414 Debug.resetGlobalAllocSize();
415 }
416 int id = ar.getResourceId(i, 0);
Joe Onorato43a17652011-04-06 19:22:23 -0700417 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
419 }
420 if (id != 0) {
Dianne Hackborndde331c2012-08-03 14:01:57 -0700421 if (mResources.getDrawable(id) == null) {
422 throw new IllegalArgumentException(
423 "Unable to find preloaded drawable resource #0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 + Integer.toHexString(id)
Dianne Hackborndde331c2012-08-03 14:01:57 -0700425 + " (" + ar.getString(i) + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 }
427 }
428 }
429 return N;
430 }
431
432 /**
433 * Runs several special GCs to try to clean up a few generations of
434 * softly- and final-reachable objects, along with any other garbage.
435 * This is only useful just before a fork().
436 */
437 /*package*/ static void gc() {
438 final VMRuntime runtime = VMRuntime.getRuntime();
439
440 /* runFinalizationSync() lets finalizers be called in Zygote,
441 * which doesn't have a HeapWorker thread.
442 */
Brian Carlstrom08065b92011-04-01 15:49:41 -0700443 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 runtime.runFinalizationSync();
Brian Carlstrom08065b92011-04-01 15:49:41 -0700445 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 runtime.runFinalizationSync();
Brian Carlstrom08065b92011-04-01 15:49:41 -0700447 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 runtime.runFinalizationSync();
449 }
450
451 /**
452 * Finish remaining work for the newly forked system server process.
453 */
454 private static void handleSystemServerProcess(
455 ZygoteConnection.Arguments parsedArgs)
456 throws ZygoteInit.MethodAndArgsCaller {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457
458 closeServerSocket();
459
Mike Lockwood90960e82010-08-06 09:15:25 -0400460 // set umask to 0077 so new files and directories will default to owner-only permissions.
Kenny Root4c74f8c2012-08-17 08:45:55 -0700461 Libcore.os.umask(S_IRWXG | S_IRWXO);
Mike Lockwood90960e82010-08-06 09:15:25 -0400462
Jeff Brownebed7d62011-05-16 17:08:42 -0700463 if (parsedArgs.niceName != null) {
464 Process.setArgV0(parsedArgs.niceName);
465 }
466
467 if (parsedArgs.invokeWith != null) {
468 WrapperInit.execApplication(parsedArgs.invokeWith,
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700469 parsedArgs.niceName, parsedArgs.targetSdkVersion,
470 null, parsedArgs.remainingArgs);
Jeff Brownebed7d62011-05-16 17:08:42 -0700471 } else {
472 /*
473 * Pass the remaining arguments to SystemServer.
474 */
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700475 RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
Jeff Brownebed7d62011-05-16 17:08:42 -0700476 }
477
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 /* should never reach here */
479 }
480
481 /**
482 * Prepare the arguments and fork for the system server process.
483 */
Bob Leee5408332009-09-04 18:31:17 -0700484 private static boolean startSystemServer()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 throws MethodAndArgsCaller, RuntimeException {
Alex Klyubin48a06e72013-04-19 10:01:42 -0700486 long capabilities = posixCapabilitiesAsBits(
487 OsConstants.CAP_KILL,
488 OsConstants.CAP_NET_ADMIN,
489 OsConstants.CAP_NET_BIND_SERVICE,
490 OsConstants.CAP_NET_BROADCAST,
491 OsConstants.CAP_NET_RAW,
Alex Klyubin48a06e72013-04-19 10:01:42 -0700492 OsConstants.CAP_SYS_MODULE,
493 OsConstants.CAP_SYS_NICE,
494 OsConstants.CAP_SYS_RESOURCE,
495 OsConstants.CAP_SYS_TIME,
496 OsConstants.CAP_SYS_TTY_CONFIG
497 );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 /* Hardcoded command line to start the system server */
499 String args[] = {
500 "--setuid=1000",
501 "--setgid=1000",
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700502 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003,3006,3007",
Alex Klyubin48a06e72013-04-19 10:01:42 -0700503 "--capabilities=" + capabilities + "," + capabilities,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 "--runtime-init",
505 "--nice-name=system_server",
506 "com.android.server.SystemServer",
507 };
508 ZygoteConnection.Arguments parsedArgs = null;
509
510 int pid;
511
512 try {
513 parsedArgs = new ZygoteConnection.Arguments(args);
Jeff Brownebed7d62011-05-16 17:08:42 -0700514 ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
515 ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516
517 /* Request to fork the system server process */
518 pid = Zygote.forkSystemServer(
519 parsedArgs.uid, parsedArgs.gid,
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700520 parsedArgs.gids,
521 parsedArgs.debugFlags,
522 null,
Andy McFadden1b4c7962010-10-27 11:26:05 -0700523 parsedArgs.permittedCapabilities,
524 parsedArgs.effectiveCapabilities);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525 } catch (IllegalArgumentException ex) {
526 throw new RuntimeException(ex);
Bob Leee5408332009-09-04 18:31:17 -0700527 }
528
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 /* For child process */
530 if (pid == 0) {
531 handleSystemServerProcess(parsedArgs);
532 }
533
534 return true;
535 }
536
Alex Klyubin48a06e72013-04-19 10:01:42 -0700537 /**
538 * Gets the bit array representation of the provided list of POSIX capabilities.
539 */
540 private static long posixCapabilitiesAsBits(int... capabilities) {
541 long result = 0;
542 for (int capability : capabilities) {
543 if ((capability < 0) || (capability > OsConstants.CAP_LAST_CAP)) {
544 throw new IllegalArgumentException(String.valueOf(capability));
545 }
546 result |= (1L << capability);
547 }
548 return result;
549 }
550
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 public static void main(String argv[]) {
552 try {
Bob Leee5408332009-09-04 18:31:17 -0700553 // Start profiling the zygote initialization.
554 SamplingProfilerIntegration.start();
555
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 registerZygoteSocket();
557 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
558 SystemClock.uptimeMillis());
Jeff Brown0c2313d2011-06-10 22:46:40 -0700559 preload();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
561 SystemClock.uptimeMillis());
562
Brian Carlstrom17510862010-08-18 14:27:40 -0700563 // Finish profiling the zygote initialization.
564 SamplingProfilerIntegration.writeZygoteSnapshot();
Bob Leee5408332009-09-04 18:31:17 -0700565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 // Do an initial gc to clean up after startup
567 gc();
568
Jamie Gennis6ad04522013-04-15 18:53:24 -0700569 // Disable tracing so that forked processes do not inherit stale tracing tags from
570 // Zygote.
571 Trace.setTracingEnabled(false);
572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 // If requested, start system server directly from Zygote
574 if (argv.length != 2) {
Barry Hayes0b3533a2010-01-20 12:46:47 -0800575 throw new RuntimeException(argv[0] + USAGE_STRING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 }
577
Jeff Brownebed7d62011-05-16 17:08:42 -0700578 if (argv[1].equals("start-system-server")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 startSystemServer();
Jeff Brownebed7d62011-05-16 17:08:42 -0700580 } else if (!argv[1].equals("")) {
Barry Hayes0b3533a2010-01-20 12:46:47 -0800581 throw new RuntimeException(argv[0] + USAGE_STRING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 }
583
584 Log.i(TAG, "Accepting command socket connections");
585
Nick Kralevichcae3d9f2013-01-30 09:51:40 -0800586 runSelectLoop();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587
588 closeServerSocket();
589 } catch (MethodAndArgsCaller caller) {
590 caller.run();
591 } catch (RuntimeException ex) {
592 Log.e(TAG, "Zygote died with exception", ex);
593 closeServerSocket();
594 throw ex;
595 }
596 }
597
598 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 * Runs the zygote process's select loop. Accepts new connections as
600 * they happen, and reads commands from connections one spawn-request's
601 * worth at a time.
602 *
603 * @throws MethodAndArgsCaller in a child process when a main() should
604 * be executed.
605 */
Nick Kralevichcae3d9f2013-01-30 09:51:40 -0800606 private static void runSelectLoop() throws MethodAndArgsCaller {
607 ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
608 ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 FileDescriptor[] fdArray = new FileDescriptor[4];
610
611 fds.add(sServerSocket.getFileDescriptor());
612 peers.add(null);
613
614 int loopCount = GC_LOOP_COUNT;
615 while (true) {
616 int index;
617
618 /*
619 * Call gc() before we block in select().
620 * It's work that has to be done anyway, and it's better
621 * to avoid making every child do it. It will also
622 * madvise() any free memory as a side-effect.
623 *
624 * Don't call it every time, because walking the entire
625 * heap is a lot of overhead to free a few hundred bytes.
626 */
627 if (loopCount <= 0) {
628 gc();
629 loopCount = GC_LOOP_COUNT;
630 } else {
631 loopCount--;
632 }
633
634
635 try {
636 fdArray = fds.toArray(fdArray);
637 index = selectReadable(fdArray);
638 } catch (IOException ex) {
639 throw new RuntimeException("Error in select()", ex);
640 }
641
642 if (index < 0) {
643 throw new RuntimeException("Error in select()");
644 } else if (index == 0) {
645 ZygoteConnection newPeer = acceptCommandPeer();
646 peers.add(newPeer);
647 fds.add(newPeer.getFileDesciptor());
648 } else {
649 boolean done;
650 done = peers.get(index).runOnce();
651
652 if (done) {
653 peers.remove(index);
654 fds.remove(index);
655 }
656 }
657 }
658 }
659
660 /**
661 * The Linux syscall "setreuid()"
662 * @param ruid real uid
663 * @param euid effective uid
664 * @return 0 on success, non-zero errno on fail
665 */
666 static native int setreuid(int ruid, int euid);
667
668 /**
669 * The Linux syscall "setregid()"
670 * @param rgid real gid
671 * @param egid effective gid
672 * @return 0 on success, non-zero errno on fail
673 */
674 static native int setregid(int rgid, int egid);
675
676 /**
677 * Invokes the linux syscall "setpgid"
678 *
679 * @param pid pid to change
680 * @param pgid new process group of pid
681 * @return 0 on success or non-zero errno on fail
682 */
683 static native int setpgid(int pid, int pgid);
684
685 /**
686 * Invokes the linux syscall "getpgid"
687 *
688 * @param pid pid to query
689 * @return pgid of pid in question
690 * @throws IOException on error
691 */
692 static native int getpgid(int pid) throws IOException;
693
694 /**
695 * Invokes the syscall dup2() to copy the specified descriptors into
696 * stdin, stdout, and stderr. The existing stdio descriptors will be
697 * closed and errors during close will be ignored. The specified
698 * descriptors will also remain open at their original descriptor numbers,
699 * so the caller may want to close the original descriptors.
700 *
701 * @param in new stdin
702 * @param out new stdout
703 * @param err new stderr
704 * @throws IOException
705 */
706 static native void reopenStdio(FileDescriptor in,
707 FileDescriptor out, FileDescriptor err) throws IOException;
708
709 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710 * Toggles the close-on-exec flag for the specified file descriptor.
711 *
712 * @param fd non-null; file descriptor
713 * @param flag desired close-on-exec flag state
714 * @throws IOException
715 */
716 static native void setCloseOnExec(FileDescriptor fd, boolean flag)
717 throws IOException;
718
719 /**
720 * Retrieves the permitted capability set from another process.
721 *
722 * @param pid &gt;=0 process ID or 0 for this process
723 * @throws IOException on error
724 */
725 static native long capgetPermitted(int pid)
726 throws IOException;
727
728 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 * Invokes select() on the provider array of file descriptors (selecting
730 * for readability only). Array elements of null are ignored.
731 *
732 * @param fds non-null; array of readable file descriptors
733 * @return index of descriptor that is now readable or -1 for empty array.
734 * @throws IOException if an error occurs
735 */
736 static native int selectReadable(FileDescriptor[] fds) throws IOException;
737
738 /**
739 * Creates a file descriptor from an int fd.
740 *
741 * @param fd integer OS file descriptor
742 * @return non-null; FileDescriptor instance
743 * @throws IOException if fd is invalid
744 */
745 static native FileDescriptor createFileDescriptor(int fd)
746 throws IOException;
747
748 /**
749 * Class not instantiable.
750 */
751 private ZygoteInit() {
752 }
753
754 /**
755 * Helper exception class which holds a method and arguments and
756 * can call them. This is used as part of a trampoline to get rid of
757 * the initial process setup stack frames.
758 */
759 public static class MethodAndArgsCaller extends Exception
760 implements Runnable {
761 /** method to call */
762 private final Method mMethod;
763
764 /** argument array */
765 private final String[] mArgs;
766
767 public MethodAndArgsCaller(Method method, String[] args) {
768 mMethod = method;
769 mArgs = args;
770 }
771
772 public void run() {
773 try {
774 mMethod.invoke(null, new Object[] { mArgs });
775 } catch (IllegalAccessException ex) {
776 throw new RuntimeException(ex);
777 } catch (InvocationTargetException ex) {
778 Throwable cause = ex.getCause();
779 if (cause instanceof RuntimeException) {
780 throw (RuntimeException) cause;
781 } else if (cause instanceof Error) {
782 throw (Error) cause;
783 }
784 throw new RuntimeException(ex);
785 }
786 }
787 }
788}