blob: 1a83bceff41c9430832aecc34b6fd5b4a0274e50 [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;
Elliott Hughes860c5912014-04-28 19:19:13 -070031import android.system.Os;
32import android.system.OsConstants;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.util.EventLog;
34import android.util.Log;
35
36import dalvik.system.VMRuntime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037
Brian Carlstrom46703b02011-04-06 15:41:29 -070038import libcore.io.IoUtils;
39
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import java.io.BufferedReader;
41import java.io.FileDescriptor;
42import java.io.IOException;
43import java.io.InputStream;
44import java.io.InputStreamReader;
45import java.lang.reflect.InvocationTargetException;
46import java.lang.reflect.Method;
47import java.lang.reflect.Modifier;
48import java.util.ArrayList;
49
50/**
51 * Startup class for the zygote process.
52 *
53 * Pre-initializes some classes, and then waits for commands on a UNIX domain
Elliott Hughese1dfcb72011-07-08 11:08:07 -070054 * socket. Based on these commands, forks off child processes that inherit
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055 * the initial state of the VM.
56 *
57 * Please see {@link ZygoteConnection.Arguments} for documentation on the
58 * client protocol.
59 *
60 * @hide
61 */
62public class ZygoteInit {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063 private static final String TAG = "Zygote";
64
Romain Guyc5e36382013-05-09 11:08:17 -070065 private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
66
Narayan Kamathc41638c2014-04-07 13:56:15 +010067 private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068
69 private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
70 private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
71
72 /** when preloading, GC after allocating this many bytes */
73 private static final int PRELOAD_GC_THRESHOLD = 50000;
74
Narayan Kamathc41638c2014-04-07 13:56:15 +010075 private static final String ABI_LIST_ARG = "--abi-list=";
76
77 private static final String SOCKET_NAME_ARG = "--socket-name=";
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 */
Narayan Kamathc41638c2014-04-07 13:56:15 +0100154 private static void registerZygoteSocket(String socketName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 if (sServerSocket == null) {
156 int fileDesc;
Narayan Kamathc41638c2014-04-07 13:56:15 +0100157 final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 try {
Narayan Kamathc41638c2014-04-07 13:56:15 +0100159 String env = System.getenv(fullSocketName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 fileDesc = Integer.parseInt(env);
161 } catch (RuntimeException ex) {
Narayan Kamathc41638c2014-04-07 13:56:15 +0100162 throw new RuntimeException(fullSocketName + " unset or invalid", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 }
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 */
Narayan Kamathc41638c2014-04-07 13:56:15 +0100179 private static ZygoteConnection acceptCommandPeer(String abiList) {
Bob Leee5408332009-09-04 18:31:17 -0700180 try {
Narayan Kamathc41638c2014-04-07 13:56:15 +0100181 return new ZygoteConnection(sServerSocket.accept(), abiList);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 } 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
Dave Platt89d4c892014-02-05 17:06:42 -0800204 /**
205 * Return the server socket's underlying file descriptor, so that
206 * ZygoteConnection can pass it to the native code for proper
207 * closure after a child process is forked off.
208 */
209
210 static FileDescriptor getServerSocketFileDescriptor() {
211 return sServerSocket.getFileDescriptor();
212 }
213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 private static final int UNPRIVILEGED_UID = 9999;
215 private static final int UNPRIVILEGED_GID = 9999;
216
217 private static final int ROOT_UID = 0;
218 private static final int ROOT_GID = 0;
219
220 /**
221 * Sets effective user ID.
222 */
223 private static void setEffectiveUser(int uid) {
224 int errno = setreuid(ROOT_UID, uid);
225 if (errno != 0) {
226 Log.e(TAG, "setreuid() failed. errno: " + errno);
227 }
228 }
229
230 /**
231 * Sets effective group ID.
232 */
233 private static void setEffectiveGroup(int gid) {
234 int errno = setregid(ROOT_GID, gid);
235 if (errno != 0) {
236 Log.e(TAG, "setregid() failed. errno: " + errno);
237 }
238 }
239
Jeff Brown0c2313d2011-06-10 22:46:40 -0700240 static void preload() {
241 preloadClasses();
242 preloadResources();
Romain Guy74c69122013-05-08 17:54:20 -0700243 preloadOpenGL();
244 }
245
246 private static void preloadOpenGL() {
Romain Guyc5e36382013-05-09 11:08:17 -0700247 if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false)) {
248 EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
249 }
Jeff Brown0c2313d2011-06-10 22:46:40 -0700250 }
251
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 /**
253 * Performs Zygote process initialization. Loads and initializes
254 * commonly used classes.
255 *
256 * Most classes only cause a few hundred bytes to be allocated, but
257 * a few will allocate a dozen Kbytes (in one case, 500+K).
258 */
259 private static void preloadClasses() {
260 final VMRuntime runtime = VMRuntime.getRuntime();
Bob Leee5408332009-09-04 18:31:17 -0700261
Andy McFaddendc7bf5d2012-01-23 09:48:53 -0800262 InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 PRELOADED_CLASSES);
264 if (is == null) {
265 Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
266 } else {
267 Log.i(TAG, "Preloading classes...");
268 long startTime = SystemClock.uptimeMillis();
Bob Leee5408332009-09-04 18:31:17 -0700269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 // Drop root perms while running static initializers.
271 setEffectiveGroup(UNPRIVILEGED_GID);
272 setEffectiveUser(UNPRIVILEGED_UID);
273
274 // Alter the target heap utilization. With explicit GCs this
275 // is not likely to have any effect.
276 float defaultUtilization = runtime.getTargetHeapUtilization();
277 runtime.setTargetHeapUtilization(0.8f);
278
279 // Start with a clean slate.
Brian Carlstrom08065b92011-04-01 15:49:41 -0700280 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 runtime.runFinalizationSync();
282 Debug.startAllocCounting();
283
284 try {
Bob Leee5408332009-09-04 18:31:17 -0700285 BufferedReader br
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 = new BufferedReader(new InputStreamReader(is), 256);
287
288 int count = 0;
289 String line;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 while ((line = br.readLine()) != null) {
291 // Skip comments and blank lines.
292 line = line.trim();
293 if (line.startsWith("#") || line.equals("")) {
294 continue;
295 }
296
297 try {
Joe Onorato43a17652011-04-06 19:22:23 -0700298 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 Log.v(TAG, "Preloading " + line + "...");
300 }
301 Class.forName(line);
302 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700303 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 Log.v(TAG,
305 " GC at " + Debug.getGlobalAllocSize());
306 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700307 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 runtime.runFinalizationSync();
309 Debug.resetGlobalAllocSize();
310 }
311 count++;
312 } catch (ClassNotFoundException e) {
Jesse Wilsone2417542010-06-03 12:33:26 -0700313 Log.w(TAG, "Class not found for preloading: " + line);
Brian Carlstromad13bd52013-11-03 22:47:11 -0800314 } catch (UnsatisfiedLinkError e) {
315 Log.w(TAG, "Problem preloading " + line + ": " + e);
Bob Lee2e93f652009-08-11 01:16:03 -0700316 } catch (Throwable t) {
317 Log.e(TAG, "Error preloading " + line + ".", t);
318 if (t instanceof Error) {
319 throw (Error) t;
320 }
321 if (t instanceof RuntimeException) {
322 throw (RuntimeException) t;
323 }
324 throw new RuntimeException(t);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 }
326 }
327
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 Log.i(TAG, "...preloaded " + count + " classes in "
329 + (SystemClock.uptimeMillis()-startTime) + "ms.");
330 } catch (IOException e) {
331 Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
332 } finally {
Brian Carlstrom46703b02011-04-06 15:41:29 -0700333 IoUtils.closeQuietly(is);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 // Restore default.
335 runtime.setTargetHeapUtilization(defaultUtilization);
336
Brian Carlstrom6c3baf12013-10-07 17:47:37 -0700337 // Fill in dex caches with classes, fields, and methods brought in by preloading.
338 runtime.preloadDexCaches();
339
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 Debug.stopAllocCounting();
341
342 // Bring back root. We'll need it later.
343 setEffectiveUser(ROOT_UID);
344 setEffectiveGroup(ROOT_GID);
345 }
346 }
347 }
348
349 /**
350 * Load in commonly used resources, so they can be shared across
351 * processes.
352 *
353 * These tend to be a few Kbytes, but are frequently in the 20-40K
354 * range, and occasionally even larger.
355 */
356 private static void preloadResources() {
357 final VMRuntime runtime = VMRuntime.getRuntime();
Bob Leee5408332009-09-04 18:31:17 -0700358
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 Debug.startAllocCounting();
360 try {
Brian Carlstrom08065b92011-04-01 15:49:41 -0700361 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 runtime.runFinalizationSync();
363 mResources = Resources.getSystem();
364 mResources.startPreloading();
365 if (PRELOAD_RESOURCES) {
366 Log.i(TAG, "Preloading resources...");
367
368 long startTime = SystemClock.uptimeMillis();
369 TypedArray ar = mResources.obtainTypedArray(
370 com.android.internal.R.array.preloaded_drawables);
371 int N = preloadDrawables(runtime, ar);
Jeff Brown14577c42012-03-08 16:40:14 -0800372 ar.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 Log.i(TAG, "...preloaded " + N + " resources in "
374 + (SystemClock.uptimeMillis()-startTime) + "ms.");
375
376 startTime = SystemClock.uptimeMillis();
377 ar = mResources.obtainTypedArray(
378 com.android.internal.R.array.preloaded_color_state_lists);
379 N = preloadColorStateLists(runtime, ar);
Jeff Brown14577c42012-03-08 16:40:14 -0800380 ar.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 Log.i(TAG, "...preloaded " + N + " resources in "
382 + (SystemClock.uptimeMillis()-startTime) + "ms.");
383 }
384 mResources.finishPreloading();
385 } catch (RuntimeException e) {
386 Log.w(TAG, "Failure preloading resources", e);
387 } finally {
388 Debug.stopAllocCounting();
389 }
390 }
391
392 private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) {
393 int N = ar.length();
394 for (int i=0; i<N; i++) {
395 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700396 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
398 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700399 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 runtime.runFinalizationSync();
401 Debug.resetGlobalAllocSize();
402 }
403 int id = ar.getResourceId(i, 0);
Joe Onorato43a17652011-04-06 19:22:23 -0700404 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
406 }
407 if (id != 0) {
Dianne Hackborndde331c2012-08-03 14:01:57 -0700408 if (mResources.getColorStateList(id) == null) {
409 throw new IllegalArgumentException(
410 "Unable to find preloaded color resource #0x"
411 + Integer.toHexString(id)
412 + " (" + ar.getString(i) + ")");
413 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 }
415 }
416 return N;
417 }
418
419
420 private static int preloadDrawables(VMRuntime runtime, TypedArray ar) {
421 int N = ar.length();
422 for (int i=0; i<N; i++) {
423 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
Joe Onorato43a17652011-04-06 19:22:23 -0700424 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425 Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
426 }
Brian Carlstrom08065b92011-04-01 15:49:41 -0700427 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 runtime.runFinalizationSync();
429 Debug.resetGlobalAllocSize();
430 }
431 int id = ar.getResourceId(i, 0);
Joe Onorato43a17652011-04-06 19:22:23 -0700432 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
434 }
435 if (id != 0) {
Dianne Hackborndde331c2012-08-03 14:01:57 -0700436 if (mResources.getDrawable(id) == null) {
437 throw new IllegalArgumentException(
438 "Unable to find preloaded drawable resource #0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 + Integer.toHexString(id)
Dianne Hackborndde331c2012-08-03 14:01:57 -0700440 + " (" + ar.getString(i) + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 }
442 }
443 }
444 return N;
445 }
446
447 /**
448 * Runs several special GCs to try to clean up a few generations of
449 * softly- and final-reachable objects, along with any other garbage.
450 * This is only useful just before a fork().
451 */
452 /*package*/ static void gc() {
453 final VMRuntime runtime = VMRuntime.getRuntime();
454
455 /* runFinalizationSync() lets finalizers be called in Zygote,
456 * which doesn't have a HeapWorker thread.
457 */
Brian Carlstrom08065b92011-04-01 15:49:41 -0700458 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 runtime.runFinalizationSync();
Brian Carlstrom08065b92011-04-01 15:49:41 -0700460 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 runtime.runFinalizationSync();
Brian Carlstrom08065b92011-04-01 15:49:41 -0700462 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 runtime.runFinalizationSync();
464 }
465
466 /**
467 * Finish remaining work for the newly forked system server process.
468 */
469 private static void handleSystemServerProcess(
470 ZygoteConnection.Arguments parsedArgs)
471 throws ZygoteInit.MethodAndArgsCaller {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472
473 closeServerSocket();
474
Mike Lockwood90960e82010-08-06 09:15:25 -0400475 // set umask to 0077 so new files and directories will default to owner-only permissions.
Elliott Hughes860c5912014-04-28 19:19:13 -0700476 Os.umask(S_IRWXG | S_IRWXO);
Mike Lockwood90960e82010-08-06 09:15:25 -0400477
Jeff Brownebed7d62011-05-16 17:08:42 -0700478 if (parsedArgs.niceName != null) {
479 Process.setArgV0(parsedArgs.niceName);
480 }
481
482 if (parsedArgs.invokeWith != null) {
483 WrapperInit.execApplication(parsedArgs.invokeWith,
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700484 parsedArgs.niceName, parsedArgs.targetSdkVersion,
485 null, parsedArgs.remainingArgs);
Jeff Brownebed7d62011-05-16 17:08:42 -0700486 } else {
487 /*
488 * Pass the remaining arguments to SystemServer.
489 */
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700490 RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
Jeff Brownebed7d62011-05-16 17:08:42 -0700491 }
492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 /* should never reach here */
494 }
495
496 /**
497 * Prepare the arguments and fork for the system server process.
498 */
Bob Leee5408332009-09-04 18:31:17 -0700499 private static boolean startSystemServer()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 throws MethodAndArgsCaller, RuntimeException {
Alex Klyubin48a06e72013-04-19 10:01:42 -0700501 long capabilities = posixCapabilitiesAsBits(
Daniel Leung49cbafa2013-12-20 10:37:35 -0800502 OsConstants.CAP_BLOCK_SUSPEND,
Alex Klyubin48a06e72013-04-19 10:01:42 -0700503 OsConstants.CAP_KILL,
504 OsConstants.CAP_NET_ADMIN,
505 OsConstants.CAP_NET_BIND_SERVICE,
506 OsConstants.CAP_NET_BROADCAST,
507 OsConstants.CAP_NET_RAW,
Alex Klyubin48a06e72013-04-19 10:01:42 -0700508 OsConstants.CAP_SYS_MODULE,
509 OsConstants.CAP_SYS_NICE,
510 OsConstants.CAP_SYS_RESOURCE,
511 OsConstants.CAP_SYS_TIME,
512 OsConstants.CAP_SYS_TTY_CONFIG
513 );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800514 /* Hardcoded command line to start the system server */
515 String args[] = {
516 "--setuid=1000",
517 "--setgid=1000",
Jeff Sharkey184a0102013-07-10 16:19:52 -0700518 "--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 -0700519 "--capabilities=" + capabilities + "," + capabilities,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 "--runtime-init",
521 "--nice-name=system_server",
522 "com.android.server.SystemServer",
523 };
524 ZygoteConnection.Arguments parsedArgs = null;
525
526 int pid;
527
528 try {
529 parsedArgs = new ZygoteConnection.Arguments(args);
Jeff Brownebed7d62011-05-16 17:08:42 -0700530 ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
531 ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532
533 /* Request to fork the system server process */
534 pid = Zygote.forkSystemServer(
535 parsedArgs.uid, parsedArgs.gid,
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700536 parsedArgs.gids,
537 parsedArgs.debugFlags,
538 null,
Andy McFadden1b4c7962010-10-27 11:26:05 -0700539 parsedArgs.permittedCapabilities,
540 parsedArgs.effectiveCapabilities);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 } catch (IllegalArgumentException ex) {
542 throw new RuntimeException(ex);
Bob Leee5408332009-09-04 18:31:17 -0700543 }
544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 /* For child process */
546 if (pid == 0) {
547 handleSystemServerProcess(parsedArgs);
548 }
549
550 return true;
551 }
552
Alex Klyubin48a06e72013-04-19 10:01:42 -0700553 /**
554 * Gets the bit array representation of the provided list of POSIX capabilities.
555 */
556 private static long posixCapabilitiesAsBits(int... capabilities) {
557 long result = 0;
558 for (int capability : capabilities) {
559 if ((capability < 0) || (capability > OsConstants.CAP_LAST_CAP)) {
560 throw new IllegalArgumentException(String.valueOf(capability));
561 }
562 result |= (1L << capability);
563 }
564 return result;
565 }
566
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 public static void main(String argv[]) {
568 try {
Bob Leee5408332009-09-04 18:31:17 -0700569 // Start profiling the zygote initialization.
570 SamplingProfilerIntegration.start();
571
Narayan Kamathc41638c2014-04-07 13:56:15 +0100572 boolean startSystemServer = false;
573 String socketName = "zygote";
574 String abiList = null;
575 for (int i = 1; i < argv.length; i++) {
576 if ("start-system-server".equals(argv[i])) {
577 startSystemServer = true;
578 } else if (argv[i].startsWith(ABI_LIST_ARG)) {
579 abiList = argv[i].substring(ABI_LIST_ARG.length());
580 } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
581 socketName = argv[i].substring(SOCKET_NAME_ARG.length());
582 } else {
583 throw new RuntimeException("Unknown command line argument: " + argv[i]);
584 }
585 }
586
587 if (abiList == null) {
588 throw new RuntimeException("No ABI list supplied.");
589 }
590
591 registerZygoteSocket(socketName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
593 SystemClock.uptimeMillis());
Jeff Brown0c2313d2011-06-10 22:46:40 -0700594 preload();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
596 SystemClock.uptimeMillis());
597
Brian Carlstrom17510862010-08-18 14:27:40 -0700598 // Finish profiling the zygote initialization.
599 SamplingProfilerIntegration.writeZygoteSnapshot();
Bob Leee5408332009-09-04 18:31:17 -0700600
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 // Do an initial gc to clean up after startup
602 gc();
603
Jamie Gennis6ad04522013-04-15 18:53:24 -0700604 // Disable tracing so that forked processes do not inherit stale tracing tags from
605 // Zygote.
606 Trace.setTracingEnabled(false);
607
Narayan Kamathc41638c2014-04-07 13:56:15 +0100608 if (startSystemServer) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 startSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 }
611
612 Log.i(TAG, "Accepting command socket connections");
Narayan Kamathc41638c2014-04-07 13:56:15 +0100613 runSelectLoop(abiList);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614
615 closeServerSocket();
616 } catch (MethodAndArgsCaller caller) {
617 caller.run();
618 } catch (RuntimeException ex) {
619 Log.e(TAG, "Zygote died with exception", ex);
620 closeServerSocket();
621 throw ex;
622 }
623 }
624
625 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626 * Runs the zygote process's select loop. Accepts new connections as
627 * they happen, and reads commands from connections one spawn-request's
628 * worth at a time.
629 *
630 * @throws MethodAndArgsCaller in a child process when a main() should
631 * be executed.
632 */
Narayan Kamathc41638c2014-04-07 13:56:15 +0100633 private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
Nick Kralevichcae3d9f2013-01-30 09:51:40 -0800634 ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
635 ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 FileDescriptor[] fdArray = new FileDescriptor[4];
637
638 fds.add(sServerSocket.getFileDescriptor());
639 peers.add(null);
640
641 int loopCount = GC_LOOP_COUNT;
642 while (true) {
643 int index;
644
645 /*
646 * Call gc() before we block in select().
647 * It's work that has to be done anyway, and it's better
648 * to avoid making every child do it. It will also
649 * madvise() any free memory as a side-effect.
650 *
651 * Don't call it every time, because walking the entire
652 * heap is a lot of overhead to free a few hundred bytes.
653 */
654 if (loopCount <= 0) {
655 gc();
656 loopCount = GC_LOOP_COUNT;
657 } else {
658 loopCount--;
659 }
660
661
662 try {
663 fdArray = fds.toArray(fdArray);
664 index = selectReadable(fdArray);
665 } catch (IOException ex) {
666 throw new RuntimeException("Error in select()", ex);
667 }
668
669 if (index < 0) {
670 throw new RuntimeException("Error in select()");
671 } else if (index == 0) {
Narayan Kamathc41638c2014-04-07 13:56:15 +0100672 ZygoteConnection newPeer = acceptCommandPeer(abiList);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673 peers.add(newPeer);
674 fds.add(newPeer.getFileDesciptor());
675 } else {
676 boolean done;
677 done = peers.get(index).runOnce();
678
679 if (done) {
680 peers.remove(index);
681 fds.remove(index);
682 }
683 }
684 }
685 }
686
687 /**
688 * The Linux syscall "setreuid()"
689 * @param ruid real uid
690 * @param euid effective uid
691 * @return 0 on success, non-zero errno on fail
692 */
693 static native int setreuid(int ruid, int euid);
694
695 /**
696 * The Linux syscall "setregid()"
697 * @param rgid real gid
698 * @param egid effective gid
699 * @return 0 on success, non-zero errno on fail
700 */
701 static native int setregid(int rgid, int egid);
702
703 /**
704 * Invokes the linux syscall "setpgid"
705 *
706 * @param pid pid to change
707 * @param pgid new process group of pid
708 * @return 0 on success or non-zero errno on fail
709 */
710 static native int setpgid(int pid, int pgid);
711
712 /**
713 * Invokes the linux syscall "getpgid"
714 *
715 * @param pid pid to query
716 * @return pgid of pid in question
717 * @throws IOException on error
718 */
719 static native int getpgid(int pid) throws IOException;
720
721 /**
722 * Invokes the syscall dup2() to copy the specified descriptors into
723 * stdin, stdout, and stderr. The existing stdio descriptors will be
724 * closed and errors during close will be ignored. The specified
725 * descriptors will also remain open at their original descriptor numbers,
726 * so the caller may want to close the original descriptors.
727 *
728 * @param in new stdin
729 * @param out new stdout
730 * @param err new stderr
731 * @throws IOException
732 */
733 static native void reopenStdio(FileDescriptor in,
734 FileDescriptor out, FileDescriptor err) throws IOException;
735
736 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800737 * Toggles the close-on-exec flag for the specified file descriptor.
738 *
739 * @param fd non-null; file descriptor
740 * @param flag desired close-on-exec flag state
741 * @throws IOException
742 */
743 static native void setCloseOnExec(FileDescriptor fd, boolean flag)
744 throws IOException;
745
746 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 * Invokes select() on the provider array of file descriptors (selecting
748 * for readability only). Array elements of null are ignored.
749 *
750 * @param fds non-null; array of readable file descriptors
751 * @return index of descriptor that is now readable or -1 for empty array.
752 * @throws IOException if an error occurs
753 */
754 static native int selectReadable(FileDescriptor[] fds) throws IOException;
755
756 /**
757 * Creates a file descriptor from an int fd.
758 *
759 * @param fd integer OS file descriptor
760 * @return non-null; FileDescriptor instance
761 * @throws IOException if fd is invalid
762 */
763 static native FileDescriptor createFileDescriptor(int fd)
764 throws IOException;
765
766 /**
767 * Class not instantiable.
768 */
769 private ZygoteInit() {
770 }
771
772 /**
773 * Helper exception class which holds a method and arguments and
774 * can call them. This is used as part of a trampoline to get rid of
775 * the initial process setup stack frames.
776 */
777 public static class MethodAndArgsCaller extends Exception
778 implements Runnable {
779 /** method to call */
780 private final Method mMethod;
781
782 /** argument array */
783 private final String[] mArgs;
784
785 public MethodAndArgsCaller(Method method, String[] args) {
786 mMethod = method;
787 mArgs = args;
788 }
789
790 public void run() {
791 try {
792 mMethod.invoke(null, new Object[] { mArgs });
793 } catch (IllegalAccessException ex) {
794 throw new RuntimeException(ex);
795 } catch (InvocationTargetException ex) {
796 Throwable cause = ex.getCause();
797 if (cause instanceof RuntimeException) {
798 throw (RuntimeException) cause;
799 } else if (cause instanceof Error) {
800 throw (Error) cause;
801 }
802 throw new RuntimeException(ex);
803 }
804 }
805 }
806}