blob: 9dc91164c1d87d2e89b4d5acde1aa3850c6e9e29 [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) {
Dave Platt70ef29b2013-12-12 15:45:49 -0800195 FileDescriptor fd = sServerSocket.getFileDescriptor();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 sServerSocket.close();
Dave Platt70ef29b2013-12-12 15:45:49 -0800197 if (fd != null) {
198 Libcore.os.close(fd);
199 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 }
201 } catch (IOException ex) {
202 Log.e(TAG, "Zygote: error closing sockets", ex);
Dave Platt70ef29b2013-12-12 15:45:49 -0800203 } catch (libcore.io.ErrnoException ex) {
204 Log.e(TAG, "Zygote: error closing descriptor", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205 }
206
207 sServerSocket = null;
208 }
209
210 private static final int UNPRIVILEGED_UID = 9999;
211 private static final int UNPRIVILEGED_GID = 9999;
212
213 private static final int ROOT_UID = 0;
214 private static final int ROOT_GID = 0;
215
216 /**
217 * Sets effective user ID.
218 */
219 private static void setEffectiveUser(int uid) {
220 int errno = setreuid(ROOT_UID, uid);
221 if (errno != 0) {
222 Log.e(TAG, "setreuid() failed. errno: " + errno);
223 }
224 }
225
226 /**
227 * Sets effective group ID.
228 */
229 private static void setEffectiveGroup(int gid) {
230 int errno = setregid(ROOT_GID, gid);
231 if (errno != 0) {
232 Log.e(TAG, "setregid() failed. errno: " + errno);
233 }
234 }
235
Jeff Brown0c2313d2011-06-10 22:46:40 -0700236 static void preload() {
237 preloadClasses();
238 preloadResources();
Romain Guy74c69122013-05-08 17:54:20 -0700239 preloadOpenGL();
240 }
241
242 private static void preloadOpenGL() {
Romain Guyc5e36382013-05-09 11:08:17 -0700243 if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false)) {
244 EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
245 }
Jeff Brown0c2313d2011-06-10 22:46:40 -0700246 }
247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 /**
249 * Performs Zygote process initialization. Loads and initializes
250 * commonly used classes.
251 *
252 * Most classes only cause a few hundred bytes to be allocated, but
253 * a few will allocate a dozen Kbytes (in one case, 500+K).
254 */
255 private static void preloadClasses() {
256 final VMRuntime runtime = VMRuntime.getRuntime();
Bob Leee5408332009-09-04 18:31:17 -0700257
Andy McFaddendc7bf5d2012-01-23 09:48:53 -0800258 InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 PRELOADED_CLASSES);
260 if (is == null) {
261 Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
262 } else {
263 Log.i(TAG, "Preloading classes...");
264 long startTime = SystemClock.uptimeMillis();
Bob Leee5408332009-09-04 18:31:17 -0700265
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 // Drop root perms while running static initializers.
267 setEffectiveGroup(UNPRIVILEGED_GID);
268 setEffectiveUser(UNPRIVILEGED_UID);
269
270 // Alter the target heap utilization. With explicit GCs this
271 // is not likely to have any effect.
272 float defaultUtilization = runtime.getTargetHeapUtilization();
273 runtime.setTargetHeapUtilization(0.8f);
274
275 // Start with a clean slate.
Brian Carlstrom08065b92011-04-01 15:49:41 -0700276 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277 runtime.runFinalizationSync();
278 Debug.startAllocCounting();
279
280 try {
Bob Leee5408332009-09-04 18:31:17 -0700281 BufferedReader br
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 = new BufferedReader(new InputStreamReader(is), 256);
283
284 int count = 0;
285 String line;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 while ((line = br.readLine()) != null) {
287 // Skip comments and blank lines.
288 line = line.trim();
289 if (line.startsWith("#") || line.equals("")) {
290 continue;
291 }
292
293 try {
Joe Onorato43a17652011-04-06 19:22:23 -0700294 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295 Log.v(TAG, "Preloading " + line + "...");
296 }
297 Class.forName(line);
298 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700299 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 Log.v(TAG,
301 " GC at " + Debug.getGlobalAllocSize());
302 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700303 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 runtime.runFinalizationSync();
305 Debug.resetGlobalAllocSize();
306 }
307 count++;
308 } catch (ClassNotFoundException e) {
Jesse Wilsone2417542010-06-03 12:33:26 -0700309 Log.w(TAG, "Class not found for preloading: " + line);
Brian Carlstrome92f19e2013-11-03 22:47:11 -0800310 } catch (UnsatisfiedLinkError e) {
311 Log.w(TAG, "Problem preloading " + line + ": " + e);
Bob Lee2e93f652009-08-11 01:16:03 -0700312 } catch (Throwable t) {
313 Log.e(TAG, "Error preloading " + line + ".", t);
314 if (t instanceof Error) {
315 throw (Error) t;
316 }
317 if (t instanceof RuntimeException) {
318 throw (RuntimeException) t;
319 }
320 throw new RuntimeException(t);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 }
322 }
323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 Log.i(TAG, "...preloaded " + count + " classes in "
325 + (SystemClock.uptimeMillis()-startTime) + "ms.");
326 } catch (IOException e) {
327 Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
328 } finally {
Brian Carlstrom46703b02011-04-06 15:41:29 -0700329 IoUtils.closeQuietly(is);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 // Restore default.
331 runtime.setTargetHeapUtilization(defaultUtilization);
332
Brian Carlstrom6c3baf12013-10-07 17:47:37 -0700333 // Fill in dex caches with classes, fields, and methods brought in by preloading.
334 runtime.preloadDexCaches();
335
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 Debug.stopAllocCounting();
337
338 // Bring back root. We'll need it later.
339 setEffectiveUser(ROOT_UID);
340 setEffectiveGroup(ROOT_GID);
341 }
342 }
343 }
344
345 /**
346 * Load in commonly used resources, so they can be shared across
347 * processes.
348 *
349 * These tend to be a few Kbytes, but are frequently in the 20-40K
350 * range, and occasionally even larger.
351 */
352 private static void preloadResources() {
353 final VMRuntime runtime = VMRuntime.getRuntime();
Bob Leee5408332009-09-04 18:31:17 -0700354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 Debug.startAllocCounting();
356 try {
Brian Carlstrom08065b92011-04-01 15:49:41 -0700357 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 runtime.runFinalizationSync();
359 mResources = Resources.getSystem();
360 mResources.startPreloading();
361 if (PRELOAD_RESOURCES) {
362 Log.i(TAG, "Preloading resources...");
363
364 long startTime = SystemClock.uptimeMillis();
365 TypedArray ar = mResources.obtainTypedArray(
366 com.android.internal.R.array.preloaded_drawables);
367 int N = preloadDrawables(runtime, ar);
Jeff Brown14577c42012-03-08 16:40:14 -0800368 ar.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 Log.i(TAG, "...preloaded " + N + " resources in "
370 + (SystemClock.uptimeMillis()-startTime) + "ms.");
371
372 startTime = SystemClock.uptimeMillis();
373 ar = mResources.obtainTypedArray(
374 com.android.internal.R.array.preloaded_color_state_lists);
375 N = preloadColorStateLists(runtime, ar);
Jeff Brown14577c42012-03-08 16:40:14 -0800376 ar.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 Log.i(TAG, "...preloaded " + N + " resources in "
378 + (SystemClock.uptimeMillis()-startTime) + "ms.");
379 }
380 mResources.finishPreloading();
381 } catch (RuntimeException e) {
382 Log.w(TAG, "Failure preloading resources", e);
383 } finally {
384 Debug.stopAllocCounting();
385 }
386 }
387
388 private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) {
389 int N = ar.length();
390 for (int i=0; i<N; i++) {
391 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700392 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
394 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700395 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 runtime.runFinalizationSync();
397 Debug.resetGlobalAllocSize();
398 }
399 int id = ar.getResourceId(i, 0);
Joe Onorato43a17652011-04-06 19:22:23 -0700400 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
402 }
403 if (id != 0) {
Dianne Hackborndde331c2012-08-03 14:01:57 -0700404 if (mResources.getColorStateList(id) == null) {
405 throw new IllegalArgumentException(
406 "Unable to find preloaded color resource #0x"
407 + Integer.toHexString(id)
408 + " (" + ar.getString(i) + ")");
409 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 }
411 }
412 return N;
413 }
414
415
416 private static int preloadDrawables(VMRuntime runtime, TypedArray ar) {
417 int N = ar.length();
418 for (int i=0; i<N; i++) {
419 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700420 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
422 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700423 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 runtime.runFinalizationSync();
425 Debug.resetGlobalAllocSize();
426 }
427 int id = ar.getResourceId(i, 0);
Joe Onorato43a17652011-04-06 19:22:23 -0700428 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
430 }
431 if (id != 0) {
Dianne Hackborndde331c2012-08-03 14:01:57 -0700432 if (mResources.getDrawable(id) == null) {
433 throw new IllegalArgumentException(
434 "Unable to find preloaded drawable resource #0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 + Integer.toHexString(id)
Dianne Hackborndde331c2012-08-03 14:01:57 -0700436 + " (" + ar.getString(i) + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 }
438 }
439 }
440 return N;
441 }
442
443 /**
444 * Runs several special GCs to try to clean up a few generations of
445 * softly- and final-reachable objects, along with any other garbage.
446 * This is only useful just before a fork().
447 */
448 /*package*/ static void gc() {
449 final VMRuntime runtime = VMRuntime.getRuntime();
450
451 /* runFinalizationSync() lets finalizers be called in Zygote,
452 * which doesn't have a HeapWorker thread.
453 */
Brian Carlstrom08065b92011-04-01 15:49:41 -0700454 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 runtime.runFinalizationSync();
Brian Carlstrom08065b92011-04-01 15:49:41 -0700456 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 runtime.runFinalizationSync();
Brian Carlstrom08065b92011-04-01 15:49:41 -0700458 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 runtime.runFinalizationSync();
460 }
461
462 /**
463 * Finish remaining work for the newly forked system server process.
464 */
465 private static void handleSystemServerProcess(
466 ZygoteConnection.Arguments parsedArgs)
467 throws ZygoteInit.MethodAndArgsCaller {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468
469 closeServerSocket();
470
Mike Lockwood90960e82010-08-06 09:15:25 -0400471 // set umask to 0077 so new files and directories will default to owner-only permissions.
Kenny Root4c74f8c2012-08-17 08:45:55 -0700472 Libcore.os.umask(S_IRWXG | S_IRWXO);
Mike Lockwood90960e82010-08-06 09:15:25 -0400473
Jeff Brownebed7d62011-05-16 17:08:42 -0700474 if (parsedArgs.niceName != null) {
475 Process.setArgV0(parsedArgs.niceName);
476 }
477
478 if (parsedArgs.invokeWith != null) {
479 WrapperInit.execApplication(parsedArgs.invokeWith,
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700480 parsedArgs.niceName, parsedArgs.targetSdkVersion,
481 null, parsedArgs.remainingArgs);
Jeff Brownebed7d62011-05-16 17:08:42 -0700482 } else {
483 /*
484 * Pass the remaining arguments to SystemServer.
485 */
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700486 RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
Jeff Brownebed7d62011-05-16 17:08:42 -0700487 }
488
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 /* should never reach here */
490 }
491
492 /**
493 * Prepare the arguments and fork for the system server process.
494 */
Bob Leee5408332009-09-04 18:31:17 -0700495 private static boolean startSystemServer()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 throws MethodAndArgsCaller, RuntimeException {
Alex Klyubin48a06e72013-04-19 10:01:42 -0700497 long capabilities = posixCapabilitiesAsBits(
Michael Wright67774c72013-09-25 14:13:40 -0700498 OsConstants.CAP_BLOCK_SUSPEND,
Alex Klyubin48a06e72013-04-19 10:01:42 -0700499 OsConstants.CAP_KILL,
500 OsConstants.CAP_NET_ADMIN,
501 OsConstants.CAP_NET_BIND_SERVICE,
502 OsConstants.CAP_NET_BROADCAST,
503 OsConstants.CAP_NET_RAW,
Alex Klyubin48a06e72013-04-19 10:01:42 -0700504 OsConstants.CAP_SYS_MODULE,
505 OsConstants.CAP_SYS_NICE,
506 OsConstants.CAP_SYS_RESOURCE,
507 OsConstants.CAP_SYS_TIME,
508 OsConstants.CAP_SYS_TTY_CONFIG
509 );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 /* Hardcoded command line to start the system server */
511 String args[] = {
512 "--setuid=1000",
513 "--setgid=1000",
Jeff Sharkey184a0102013-07-10 16:19:52 -0700514 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
Alex Klyubin48a06e72013-04-19 10:01:42 -0700515 "--capabilities=" + capabilities + "," + capabilities,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 "--runtime-init",
517 "--nice-name=system_server",
518 "com.android.server.SystemServer",
519 };
520 ZygoteConnection.Arguments parsedArgs = null;
521
522 int pid;
523
524 try {
525 parsedArgs = new ZygoteConnection.Arguments(args);
Jeff Brownebed7d62011-05-16 17:08:42 -0700526 ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
527 ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528
529 /* Request to fork the system server process */
530 pid = Zygote.forkSystemServer(
531 parsedArgs.uid, parsedArgs.gid,
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700532 parsedArgs.gids,
533 parsedArgs.debugFlags,
534 null,
Andy McFadden1b4c7962010-10-27 11:26:05 -0700535 parsedArgs.permittedCapabilities,
536 parsedArgs.effectiveCapabilities);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 } catch (IllegalArgumentException ex) {
538 throw new RuntimeException(ex);
Bob Leee5408332009-09-04 18:31:17 -0700539 }
540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 /* For child process */
542 if (pid == 0) {
543 handleSystemServerProcess(parsedArgs);
544 }
545
546 return true;
547 }
548
Alex Klyubin48a06e72013-04-19 10:01:42 -0700549 /**
550 * Gets the bit array representation of the provided list of POSIX capabilities.
551 */
552 private static long posixCapabilitiesAsBits(int... capabilities) {
553 long result = 0;
554 for (int capability : capabilities) {
555 if ((capability < 0) || (capability > OsConstants.CAP_LAST_CAP)) {
556 throw new IllegalArgumentException(String.valueOf(capability));
557 }
558 result |= (1L << capability);
559 }
560 return result;
561 }
562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 public static void main(String argv[]) {
564 try {
Bob Leee5408332009-09-04 18:31:17 -0700565 // Start profiling the zygote initialization.
566 SamplingProfilerIntegration.start();
567
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 registerZygoteSocket();
569 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
570 SystemClock.uptimeMillis());
Jeff Brown0c2313d2011-06-10 22:46:40 -0700571 preload();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
573 SystemClock.uptimeMillis());
574
Brian Carlstrom17510862010-08-18 14:27:40 -0700575 // Finish profiling the zygote initialization.
576 SamplingProfilerIntegration.writeZygoteSnapshot();
Bob Leee5408332009-09-04 18:31:17 -0700577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 // Do an initial gc to clean up after startup
579 gc();
580
Jamie Gennis6ad04522013-04-15 18:53:24 -0700581 // Disable tracing so that forked processes do not inherit stale tracing tags from
582 // Zygote.
583 Trace.setTracingEnabled(false);
584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 // If requested, start system server directly from Zygote
586 if (argv.length != 2) {
Barry Hayes0b3533a2010-01-20 12:46:47 -0800587 throw new RuntimeException(argv[0] + USAGE_STRING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 }
589
Jeff Brownebed7d62011-05-16 17:08:42 -0700590 if (argv[1].equals("start-system-server")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 startSystemServer();
Jeff Brownebed7d62011-05-16 17:08:42 -0700592 } else if (!argv[1].equals("")) {
Barry Hayes0b3533a2010-01-20 12:46:47 -0800593 throw new RuntimeException(argv[0] + USAGE_STRING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 }
595
596 Log.i(TAG, "Accepting command socket connections");
597
Nick Kralevichcae3d9f2013-01-30 09:51:40 -0800598 runSelectLoop();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599
600 closeServerSocket();
601 } catch (MethodAndArgsCaller caller) {
602 caller.run();
603 } catch (RuntimeException ex) {
604 Log.e(TAG, "Zygote died with exception", ex);
605 closeServerSocket();
606 throw ex;
607 }
608 }
609
610 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 * Runs the zygote process's select loop. Accepts new connections as
612 * they happen, and reads commands from connections one spawn-request's
613 * worth at a time.
614 *
615 * @throws MethodAndArgsCaller in a child process when a main() should
616 * be executed.
617 */
Nick Kralevichcae3d9f2013-01-30 09:51:40 -0800618 private static void runSelectLoop() throws MethodAndArgsCaller {
619 ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
620 ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800621 FileDescriptor[] fdArray = new FileDescriptor[4];
622
623 fds.add(sServerSocket.getFileDescriptor());
624 peers.add(null);
625
626 int loopCount = GC_LOOP_COUNT;
627 while (true) {
628 int index;
629
630 /*
631 * Call gc() before we block in select().
632 * It's work that has to be done anyway, and it's better
633 * to avoid making every child do it. It will also
634 * madvise() any free memory as a side-effect.
635 *
636 * Don't call it every time, because walking the entire
637 * heap is a lot of overhead to free a few hundred bytes.
638 */
639 if (loopCount <= 0) {
640 gc();
641 loopCount = GC_LOOP_COUNT;
642 } else {
643 loopCount--;
644 }
645
646
647 try {
648 fdArray = fds.toArray(fdArray);
649 index = selectReadable(fdArray);
650 } catch (IOException ex) {
651 throw new RuntimeException("Error in select()", ex);
652 }
653
654 if (index < 0) {
655 throw new RuntimeException("Error in select()");
656 } else if (index == 0) {
657 ZygoteConnection newPeer = acceptCommandPeer();
658 peers.add(newPeer);
659 fds.add(newPeer.getFileDesciptor());
660 } else {
661 boolean done;
662 done = peers.get(index).runOnce();
663
664 if (done) {
665 peers.remove(index);
666 fds.remove(index);
667 }
668 }
669 }
670 }
671
672 /**
673 * The Linux syscall "setreuid()"
674 * @param ruid real uid
675 * @param euid effective uid
676 * @return 0 on success, non-zero errno on fail
677 */
678 static native int setreuid(int ruid, int euid);
679
680 /**
681 * The Linux syscall "setregid()"
682 * @param rgid real gid
683 * @param egid effective gid
684 * @return 0 on success, non-zero errno on fail
685 */
686 static native int setregid(int rgid, int egid);
687
688 /**
689 * Invokes the linux syscall "setpgid"
690 *
691 * @param pid pid to change
692 * @param pgid new process group of pid
693 * @return 0 on success or non-zero errno on fail
694 */
695 static native int setpgid(int pid, int pgid);
696
697 /**
698 * Invokes the linux syscall "getpgid"
699 *
700 * @param pid pid to query
701 * @return pgid of pid in question
702 * @throws IOException on error
703 */
704 static native int getpgid(int pid) throws IOException;
705
706 /**
707 * Invokes the syscall dup2() to copy the specified descriptors into
708 * stdin, stdout, and stderr. The existing stdio descriptors will be
709 * closed and errors during close will be ignored. The specified
710 * descriptors will also remain open at their original descriptor numbers,
711 * so the caller may want to close the original descriptors.
712 *
713 * @param in new stdin
714 * @param out new stdout
715 * @param err new stderr
716 * @throws IOException
717 */
718 static native void reopenStdio(FileDescriptor in,
719 FileDescriptor out, FileDescriptor err) throws IOException;
720
721 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800722 * Toggles the close-on-exec flag for the specified file descriptor.
723 *
724 * @param fd non-null; file descriptor
725 * @param flag desired close-on-exec flag state
726 * @throws IOException
727 */
728 static native void setCloseOnExec(FileDescriptor fd, boolean flag)
729 throws IOException;
730
731 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 * Invokes select() on the provider array of file descriptors (selecting
733 * for readability only). Array elements of null are ignored.
734 *
735 * @param fds non-null; array of readable file descriptors
736 * @return index of descriptor that is now readable or -1 for empty array.
737 * @throws IOException if an error occurs
738 */
739 static native int selectReadable(FileDescriptor[] fds) throws IOException;
740
741 /**
742 * Creates a file descriptor from an int fd.
743 *
744 * @param fd integer OS file descriptor
745 * @return non-null; FileDescriptor instance
746 * @throws IOException if fd is invalid
747 */
748 static native FileDescriptor createFileDescriptor(int fd)
749 throws IOException;
750
751 /**
752 * Class not instantiable.
753 */
754 private ZygoteInit() {
755 }
756
757 /**
758 * Helper exception class which holds a method and arguments and
759 * can call them. This is used as part of a trampoline to get rid of
760 * the initial process setup stack frames.
761 */
762 public static class MethodAndArgsCaller extends Exception
763 implements Runnable {
764 /** method to call */
765 private final Method mMethod;
766
767 /** argument array */
768 private final String[] mArgs;
769
770 public MethodAndArgsCaller(Method method, String[] args) {
771 mMethod = method;
772 mArgs = args;
773 }
774
775 public void run() {
776 try {
777 mMethod.invoke(null, new Object[] { mArgs });
778 } catch (IllegalAccessException ex) {
779 throw new RuntimeException(ex);
780 } catch (InvocationTargetException ex) {
781 Throwable cause = ex.getCause();
782 if (cause instanceof RuntimeException) {
783 throw (RuntimeException) cause;
784 } else if (cause instanceof Error) {
785 throw (Error) cause;
786 }
787 throw new RuntimeException(ex);
788 }
789 }
790 }
791}