blob: 9ca937c167fea0774061db00f4047e02b2df73cc [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
Elliott Hughes894724b2014-12-15 12:39:51 -080019import static android.system.OsConstants.POLLIN;
Elliott Hughesa9569ff2014-04-28 20:53:52 -070020import static android.system.OsConstants.S_IRWXG;
21import static android.system.OsConstants.S_IRWXO;
Kenny Root4c74f8c2012-08-17 08:45:55 -070022
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.content.res.Resources;
24import android.content.res.TypedArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.net.LocalServerSocket;
Romain Guy74c69122013-05-08 17:54:20 -070026import android.opengl.EGL14;
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;
Bill Yi9a76e9b2014-04-29 18:52:48 -070031import android.system.ErrnoException;
Elliott Hughes860c5912014-04-28 19:19:13 -070032import android.system.Os;
33import android.system.OsConstants;
Elliott Hughes894724b2014-12-15 12:39:51 -080034import android.system.StructPollfd;
Raph Levienc3dd1c12015-04-06 10:37:57 -070035import android.text.Hyphenator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.util.EventLog;
37import android.util.Log;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010038import android.webkit.WebViewFactory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039
Narayan Kamath29564cd2014-08-07 10:57:40 +010040import dalvik.system.DexFile;
41import dalvik.system.PathClassLoader;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import dalvik.system.VMRuntime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043
Brian Carlstrom46703b02011-04-06 15:41:29 -070044import libcore.io.IoUtils;
45
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import java.io.BufferedReader;
47import java.io.FileDescriptor;
Ying Wangd0c45352014-11-13 15:22:47 -080048import java.io.FileInputStream;
49import java.io.FileNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import java.io.IOException;
51import java.io.InputStream;
52import java.io.InputStreamReader;
53import java.lang.reflect.InvocationTargetException;
54import java.lang.reflect.Method;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import java.util.ArrayList;
56
57/**
58 * Startup class for the zygote process.
59 *
60 * Pre-initializes some classes, and then waits for commands on a UNIX domain
Elliott Hughese1dfcb72011-07-08 11:08:07 -070061 * socket. Based on these commands, forks off child processes that inherit
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062 * the initial state of the VM.
63 *
64 * Please see {@link ZygoteConnection.Arguments} for documentation on the
65 * client protocol.
66 *
67 * @hide
68 */
69public class ZygoteInit {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070 private static final String TAG = "Zygote";
71
Romain Guyc5e36382013-05-09 11:08:17 -070072 private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
73
Narayan Kamathc41638c2014-04-07 13:56:15 +010074 private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075
76 private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
77 private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
78
79 /** when preloading, GC after allocating this many bytes */
80 private static final int PRELOAD_GC_THRESHOLD = 50000;
81
Narayan Kamathc41638c2014-04-07 13:56:15 +010082 private static final String ABI_LIST_ARG = "--abi-list=";
83
84 private static final String SOCKET_NAME_ARG = "--socket-name=";
Barry Hayes0b3533a2010-01-20 12:46:47 -080085
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 private static LocalServerSocket sServerSocket;
87
88 /**
89 * Used to pre-load resources. We hold a global reference on it so it
90 * never gets destroyed.
91 */
92 private static Resources mResources;
Bob Leee5408332009-09-04 18:31:17 -070093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 /**
Ying Wangd0c45352014-11-13 15:22:47 -080095 * The path of a file that contains classes to preload.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 */
Ying Wangd0c45352014-11-13 15:22:47 -080097 private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098
99 /** Controls whether we should preload resources during zygote init. */
Steve Paik3c27a232015-06-10 18:25:44 -0700100 public static final boolean PRELOAD_RESOURCES = true;
Andy McFadden599c9182009-04-08 00:35:56 -0700101
102 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 * Registers a server socket for zygote command connections
104 *
105 * @throws RuntimeException when open fails
106 */
Narayan Kamathc41638c2014-04-07 13:56:15 +0100107 private static void registerZygoteSocket(String socketName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 if (sServerSocket == null) {
109 int fileDesc;
Narayan Kamathc41638c2014-04-07 13:56:15 +0100110 final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111 try {
Narayan Kamathc41638c2014-04-07 13:56:15 +0100112 String env = System.getenv(fullSocketName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 fileDesc = Integer.parseInt(env);
114 } catch (RuntimeException ex) {
Narayan Kamathc41638c2014-04-07 13:56:15 +0100115 throw new RuntimeException(fullSocketName + " unset or invalid", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 }
117
118 try {
Elliott Hughes3fe59512014-12-12 14:07:34 -0800119 FileDescriptor fd = new FileDescriptor();
120 fd.setInt$(fileDesc);
121 sServerSocket = new LocalServerSocket(fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 } catch (IOException ex) {
123 throw new RuntimeException(
124 "Error binding to local socket '" + fileDesc + "'", ex);
125 }
126 }
127 }
128
129 /**
130 * Waits for and accepts a single command connection. Throws
131 * RuntimeException on failure.
132 */
Narayan Kamathc41638c2014-04-07 13:56:15 +0100133 private static ZygoteConnection acceptCommandPeer(String abiList) {
Bob Leee5408332009-09-04 18:31:17 -0700134 try {
Narayan Kamathc41638c2014-04-07 13:56:15 +0100135 return new ZygoteConnection(sServerSocket.accept(), abiList);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 } catch (IOException ex) {
137 throw new RuntimeException(
138 "IOException during accept()", ex);
139 }
140 }
141
142 /**
143 * Close and clean up zygote sockets. Called on shutdown and on the
144 * child's exit path.
145 */
146 static void closeServerSocket() {
147 try {
148 if (sServerSocket != null) {
Dave Platt02f042d2013-12-12 15:45:49 -0800149 FileDescriptor fd = sServerSocket.getFileDescriptor();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 sServerSocket.close();
Dave Platt02f042d2013-12-12 15:45:49 -0800151 if (fd != null) {
Bill Yi9a76e9b2014-04-29 18:52:48 -0700152 Os.close(fd);
Dave Platt02f042d2013-12-12 15:45:49 -0800153 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154 }
155 } catch (IOException ex) {
156 Log.e(TAG, "Zygote: error closing sockets", ex);
Bill Yi9a76e9b2014-04-29 18:52:48 -0700157 } catch (ErrnoException ex) {
Dave Platt02f042d2013-12-12 15:45:49 -0800158 Log.e(TAG, "Zygote: error closing descriptor", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 }
160
161 sServerSocket = null;
162 }
163
Dave Platt89d4c892014-02-05 17:06:42 -0800164 /**
165 * Return the server socket's underlying file descriptor, so that
166 * ZygoteConnection can pass it to the native code for proper
167 * closure after a child process is forked off.
168 */
169
170 static FileDescriptor getServerSocketFileDescriptor() {
171 return sServerSocket.getFileDescriptor();
172 }
173
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 private static final int UNPRIVILEGED_UID = 9999;
175 private static final int UNPRIVILEGED_GID = 9999;
176
177 private static final int ROOT_UID = 0;
178 private static final int ROOT_GID = 0;
179
Jeff Brown0c2313d2011-06-10 22:46:40 -0700180 static void preload() {
Bill Yi9a76e9b2014-04-29 18:52:48 -0700181 Log.d(TAG, "begin preload");
Jeff Brown0c2313d2011-06-10 22:46:40 -0700182 preloadClasses();
183 preloadResources();
Romain Guy74c69122013-05-08 17:54:20 -0700184 preloadOpenGL();
Brian Carlstrom6c9af962014-09-11 15:36:00 -0700185 preloadSharedLibraries();
Raph Levienc3dd1c12015-04-06 10:37:57 -0700186 preloadTextResources();
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100187 // Ask the WebViewFactory to do any initialization that must run in the zygote process,
188 // for memory sharing purposes.
189 WebViewFactory.prepareWebViewInZygote();
Bill Yi9a76e9b2014-04-29 18:52:48 -0700190 Log.d(TAG, "end preload");
Romain Guy74c69122013-05-08 17:54:20 -0700191 }
192
Brian Carlstrom6c9af962014-09-11 15:36:00 -0700193 private static void preloadSharedLibraries() {
194 Log.i(TAG, "Preloading shared libraries...");
195 System.loadLibrary("android");
196 System.loadLibrary("compiler_rt");
197 System.loadLibrary("jnigraphics");
198 }
199
Romain Guy74c69122013-05-08 17:54:20 -0700200 private static void preloadOpenGL() {
Romain Guyc5e36382013-05-09 11:08:17 -0700201 if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false)) {
202 EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
203 }
Jeff Brown0c2313d2011-06-10 22:46:40 -0700204 }
205
Raph Levienc3dd1c12015-04-06 10:37:57 -0700206 private static void preloadTextResources() {
207 Hyphenator.init();
208 }
209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 /**
211 * Performs Zygote process initialization. Loads and initializes
212 * commonly used classes.
213 *
214 * Most classes only cause a few hundred bytes to be allocated, but
215 * a few will allocate a dozen Kbytes (in one case, 500+K).
216 */
217 private static void preloadClasses() {
218 final VMRuntime runtime = VMRuntime.getRuntime();
Bob Leee5408332009-09-04 18:31:17 -0700219
Ying Wangd0c45352014-11-13 15:22:47 -0800220 InputStream is;
221 try {
222 is = new FileInputStream(PRELOADED_CLASSES);
223 } catch (FileNotFoundException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
Ying Wangd0c45352014-11-13 15:22:47 -0800225 return;
226 }
Bob Leee5408332009-09-04 18:31:17 -0700227
Ying Wangd0c45352014-11-13 15:22:47 -0800228 Log.i(TAG, "Preloading classes...");
229 long startTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230
Ying Wangd0c45352014-11-13 15:22:47 -0800231 // Drop root perms while running static initializers.
Narayan Kamath23e68782015-01-16 17:22:41 +0000232 final int reuid = Os.getuid();
233 final int regid = Os.getgid();
234
235 // We need to drop root perms only if we're already root. In the case of "wrapped"
236 // processes (see WrapperInit), this function is called from an unprivileged uid
237 // and gid.
238 boolean droppedPriviliges = false;
239 if (reuid == ROOT_UID && regid == ROOT_GID) {
240 try {
241 Os.setregid(ROOT_GID, UNPRIVILEGED_GID);
242 Os.setreuid(ROOT_UID, UNPRIVILEGED_UID);
243 } catch (ErrnoException ex) {
244 throw new RuntimeException("Failed to drop root", ex);
245 }
246
247 droppedPriviliges = true;
Elliott Hughes26b56e62014-12-17 12:28:29 -0800248 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249
Ying Wangd0c45352014-11-13 15:22:47 -0800250 // Alter the target heap utilization. With explicit GCs this
251 // is not likely to have any effect.
252 float defaultUtilization = runtime.getTargetHeapUtilization();
253 runtime.setTargetHeapUtilization(0.8f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254
Ying Wangd0c45352014-11-13 15:22:47 -0800255 try {
256 BufferedReader br
257 = new BufferedReader(new InputStreamReader(is), 256);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258
Ying Wangd0c45352014-11-13 15:22:47 -0800259 int count = 0;
260 String line;
261 while ((line = br.readLine()) != null) {
262 // Skip comments and blank lines.
263 line = line.trim();
264 if (line.startsWith("#") || line.equals("")) {
265 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 }
267
Ying Wangd0c45352014-11-13 15:22:47 -0800268 try {
269 if (false) {
270 Log.v(TAG, "Preloading " + line + "...");
271 }
Andreas Gampedd8e5fb2015-04-21 09:01:51 -0700272 // Load and explicitly initialize the given class. Use
273 // Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups
274 // (to derive the caller's class-loader). Use true to force initialization, and
275 // null for the boot classpath class-loader (could as well cache the
276 // class-loader of this class in a variable).
Andreas Gampec917f742015-04-20 19:16:37 -0700277 Class.forName(line, true, null);
Ying Wangd0c45352014-11-13 15:22:47 -0800278 count++;
279 } catch (ClassNotFoundException e) {
280 Log.w(TAG, "Class not found for preloading: " + line);
281 } catch (UnsatisfiedLinkError e) {
282 Log.w(TAG, "Problem preloading " + line + ": " + e);
283 } catch (Throwable t) {
284 Log.e(TAG, "Error preloading " + line + ".", t);
285 if (t instanceof Error) {
286 throw (Error) t;
287 }
288 if (t instanceof RuntimeException) {
289 throw (RuntimeException) t;
290 }
291 throw new RuntimeException(t);
292 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 }
Ying Wangd0c45352014-11-13 15:22:47 -0800294
295 Log.i(TAG, "...preloaded " + count + " classes in "
296 + (SystemClock.uptimeMillis()-startTime) + "ms.");
297 } catch (IOException e) {
298 Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
299 } finally {
300 IoUtils.closeQuietly(is);
301 // Restore default.
302 runtime.setTargetHeapUtilization(defaultUtilization);
303
304 // Fill in dex caches with classes, fields, and methods brought in by preloading.
305 runtime.preloadDexCaches();
306
Narayan Kamath23e68782015-01-16 17:22:41 +0000307 // Bring back root. We'll need it later if we're in the zygote.
308 if (droppedPriviliges) {
309 try {
310 Os.setreuid(ROOT_UID, ROOT_UID);
311 Os.setregid(ROOT_GID, ROOT_GID);
312 } catch (ErrnoException ex) {
313 throw new RuntimeException("Failed to restore root", ex);
314 }
Elliott Hughes26b56e62014-12-17 12:28:29 -0800315 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 }
317 }
318
319 /**
320 * Load in commonly used resources, so they can be shared across
321 * processes.
322 *
323 * These tend to be a few Kbytes, but are frequently in the 20-40K
324 * range, and occasionally even larger.
325 */
326 private static void preloadResources() {
327 final VMRuntime runtime = VMRuntime.getRuntime();
Bob Leee5408332009-09-04 18:31:17 -0700328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 mResources = Resources.getSystem();
331 mResources.startPreloading();
332 if (PRELOAD_RESOURCES) {
333 Log.i(TAG, "Preloading resources...");
334
335 long startTime = SystemClock.uptimeMillis();
336 TypedArray ar = mResources.obtainTypedArray(
337 com.android.internal.R.array.preloaded_drawables);
338 int N = preloadDrawables(runtime, ar);
Jeff Brown14577c42012-03-08 16:40:14 -0800339 ar.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 Log.i(TAG, "...preloaded " + N + " resources in "
341 + (SystemClock.uptimeMillis()-startTime) + "ms.");
342
343 startTime = SystemClock.uptimeMillis();
344 ar = mResources.obtainTypedArray(
345 com.android.internal.R.array.preloaded_color_state_lists);
346 N = preloadColorStateLists(runtime, ar);
Jeff Brown14577c42012-03-08 16:40:14 -0800347 ar.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 Log.i(TAG, "...preloaded " + N + " resources in "
349 + (SystemClock.uptimeMillis()-startTime) + "ms.");
350 }
351 mResources.finishPreloading();
352 } catch (RuntimeException e) {
353 Log.w(TAG, "Failure preloading resources", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 }
355 }
356
357 private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) {
358 int N = ar.length();
359 for (int i=0; i<N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 int id = ar.getResourceId(i, 0);
Joe Onorato43a17652011-04-06 19:22:23 -0700361 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
363 }
364 if (id != 0) {
Alan Viverette77bb6f12015-02-11 17:24:33 -0800365 if (mResources.getColorStateList(id, null) == null) {
Dianne Hackborndde331c2012-08-03 14:01:57 -0700366 throw new IllegalArgumentException(
367 "Unable to find preloaded color resource #0x"
368 + Integer.toHexString(id)
369 + " (" + ar.getString(i) + ")");
370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 }
372 }
373 return N;
374 }
375
376
377 private static int preloadDrawables(VMRuntime runtime, TypedArray ar) {
378 int N = ar.length();
379 for (int i=0; i<N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 int id = ar.getResourceId(i, 0);
Joe Onorato43a17652011-04-06 19:22:23 -0700381 if (false) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
383 }
384 if (id != 0) {
Alan Viverette84e001a2014-09-22 00:04:22 -0700385 if (mResources.getDrawable(id, null) == null) {
Dianne Hackborndde331c2012-08-03 14:01:57 -0700386 throw new IllegalArgumentException(
387 "Unable to find preloaded drawable resource #0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 + Integer.toHexString(id)
Dianne Hackborndde331c2012-08-03 14:01:57 -0700389 + " (" + ar.getString(i) + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 }
391 }
392 }
393 return N;
394 }
395
396 /**
397 * Runs several special GCs to try to clean up a few generations of
398 * softly- and final-reachable objects, along with any other garbage.
399 * This is only useful just before a fork().
400 */
Mathieu Chartier9a88f102014-08-20 10:24:11 -0700401 /*package*/ static void gcAndFinalize() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 final VMRuntime runtime = VMRuntime.getRuntime();
403
404 /* runFinalizationSync() lets finalizers be called in Zygote,
405 * which doesn't have a HeapWorker thread.
406 */
Brian Carlstrom08065b92011-04-01 15:49:41 -0700407 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408 runtime.runFinalizationSync();
Brian Carlstrom08065b92011-04-01 15:49:41 -0700409 System.gc();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 }
411
412 /**
413 * Finish remaining work for the newly forked system server process.
414 */
415 private static void handleSystemServerProcess(
416 ZygoteConnection.Arguments parsedArgs)
417 throws ZygoteInit.MethodAndArgsCaller {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418
419 closeServerSocket();
420
Mike Lockwood90960e82010-08-06 09:15:25 -0400421 // set umask to 0077 so new files and directories will default to owner-only permissions.
Elliott Hughes860c5912014-04-28 19:19:13 -0700422 Os.umask(S_IRWXG | S_IRWXO);
Mike Lockwood90960e82010-08-06 09:15:25 -0400423
Jeff Brownebed7d62011-05-16 17:08:42 -0700424 if (parsedArgs.niceName != null) {
425 Process.setArgV0(parsedArgs.niceName);
426 }
427
Narayan Kamath29564cd2014-08-07 10:57:40 +0100428 final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
429 if (systemServerClasspath != null) {
430 performSystemServerDexOpt(systemServerClasspath);
431 }
432
Jeff Brownebed7d62011-05-16 17:08:42 -0700433 if (parsedArgs.invokeWith != null) {
Narayan Kamath29564cd2014-08-07 10:57:40 +0100434 String[] args = parsedArgs.remainingArgs;
435 // If we have a non-null system server class path, we'll have to duplicate the
436 // existing arguments and append the classpath to it. ART will handle the classpath
437 // correctly when we exec a new process.
438 if (systemServerClasspath != null) {
439 String[] amendedArgs = new String[args.length + 2];
440 amendedArgs[0] = "-cp";
441 amendedArgs[1] = systemServerClasspath;
442 System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length);
443 }
444
Jeff Brownebed7d62011-05-16 17:08:42 -0700445 WrapperInit.execApplication(parsedArgs.invokeWith,
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700446 parsedArgs.niceName, parsedArgs.targetSdkVersion,
Narayan Kamath37ad4b02015-01-19 16:05:24 +0000447 VMRuntime.getCurrentInstructionSet(), null, args);
Jeff Brownebed7d62011-05-16 17:08:42 -0700448 } else {
Narayan Kamath29564cd2014-08-07 10:57:40 +0100449 ClassLoader cl = null;
450 if (systemServerClasspath != null) {
451 cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
452 Thread.currentThread().setContextClassLoader(cl);
453 }
454
Jeff Brownebed7d62011-05-16 17:08:42 -0700455 /*
456 * Pass the remaining arguments to SystemServer.
457 */
Narayan Kamath29564cd2014-08-07 10:57:40 +0100458 RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
Jeff Brownebed7d62011-05-16 17:08:42 -0700459 }
460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 /* should never reach here */
462 }
463
464 /**
Narayan Kamath29564cd2014-08-07 10:57:40 +0100465 * Performs dex-opt on the elements of {@code classPath}, if needed. We
466 * choose the instruction set of the current runtime.
467 */
468 private static void performSystemServerDexOpt(String classPath) {
469 final String[] classPathElements = classPath.split(":");
470 final InstallerConnection installer = new InstallerConnection();
Makoto Onukic8a2cfe2015-06-23 16:33:48 -0700471 installer.waitForConnection();
Narayan Kamath29564cd2014-08-07 10:57:40 +0100472 final String instructionSet = VMRuntime.getRuntime().vmInstructionSet();
473
474 try {
475 for (String classPathElement : classPathElements) {
Richard Uhler7b08b352015-03-25 16:25:57 -0700476 final int dexoptNeeded = DexFile.getDexOptNeeded(
477 classPathElement, "*", instructionSet, false /* defer */);
478 if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
479 installer.dexopt(classPathElement, Process.SYSTEM_UID, false,
480 instructionSet, dexoptNeeded);
Narayan Kamath29564cd2014-08-07 10:57:40 +0100481 }
482 }
483 } catch (IOException ioe) {
484 throw new RuntimeException("Error starting system_server", ioe);
485 } finally {
486 installer.disconnect();
487 }
488 }
489
490 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 * Prepare the arguments and fork for the system server process.
492 */
Narayan Kamath64cd9072014-05-13 13:35:14 +0100493 private static boolean startSystemServer(String abiList, String socketName)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 throws MethodAndArgsCaller, RuntimeException {
Alex Klyubin48a06e72013-04-19 10:01:42 -0700495 long capabilities = posixCapabilitiesAsBits(
Daniel Leung49cbafa2013-12-20 10:37:35 -0800496 OsConstants.CAP_BLOCK_SUSPEND,
Alex Klyubin48a06e72013-04-19 10:01:42 -0700497 OsConstants.CAP_KILL,
498 OsConstants.CAP_NET_ADMIN,
499 OsConstants.CAP_NET_BIND_SERVICE,
500 OsConstants.CAP_NET_BROADCAST,
501 OsConstants.CAP_NET_RAW,
Alex Klyubin48a06e72013-04-19 10:01:42 -0700502 OsConstants.CAP_SYS_MODULE,
503 OsConstants.CAP_SYS_NICE,
504 OsConstants.CAP_SYS_RESOURCE,
505 OsConstants.CAP_SYS_TIME,
506 OsConstants.CAP_SYS_TTY_CONFIG
507 );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 /* Hardcoded command line to start the system server */
509 String args[] = {
510 "--setuid=1000",
511 "--setgid=1000",
Kevin Tangc6432e52013-07-23 10:16:48 -0700512 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007",
Alex Klyubin48a06e72013-04-19 10:01:42 -0700513 "--capabilities=" + capabilities + "," + capabilities,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800514 "--nice-name=system_server",
Narayan Kamathb6b044a2015-02-13 17:31:25 +0000515 "--runtime-args",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 "com.android.server.SystemServer",
517 };
518 ZygoteConnection.Arguments parsedArgs = null;
519
520 int pid;
521
522 try {
523 parsedArgs = new ZygoteConnection.Arguments(args);
Jeff Brownebed7d62011-05-16 17:08:42 -0700524 ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
525 ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526
527 /* Request to fork the system server process */
528 pid = Zygote.forkSystemServer(
529 parsedArgs.uid, parsedArgs.gid,
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700530 parsedArgs.gids,
531 parsedArgs.debugFlags,
532 null,
Andy McFadden1b4c7962010-10-27 11:26:05 -0700533 parsedArgs.permittedCapabilities,
534 parsedArgs.effectiveCapabilities);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 } catch (IllegalArgumentException ex) {
536 throw new RuntimeException(ex);
Bob Leee5408332009-09-04 18:31:17 -0700537 }
538
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 /* For child process */
540 if (pid == 0) {
Narayan Kamath64cd9072014-05-13 13:35:14 +0100541 if (hasSecondZygote(abiList)) {
542 waitForSecondaryZygote(socketName);
543 }
544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 handleSystemServerProcess(parsedArgs);
546 }
547
548 return true;
549 }
550
Alex Klyubin48a06e72013-04-19 10:01:42 -0700551 /**
552 * Gets the bit array representation of the provided list of POSIX capabilities.
553 */
554 private static long posixCapabilitiesAsBits(int... capabilities) {
555 long result = 0;
556 for (int capability : capabilities) {
557 if ((capability < 0) || (capability > OsConstants.CAP_LAST_CAP)) {
558 throw new IllegalArgumentException(String.valueOf(capability));
559 }
560 result |= (1L << capability);
561 }
562 return result;
563 }
564
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 public static void main(String argv[]) {
566 try {
Piotr Jastrzebskida74a622015-02-12 13:55:23 +0000567 RuntimeInit.enableDdms();
Bob Leee5408332009-09-04 18:31:17 -0700568 // Start profiling the zygote initialization.
569 SamplingProfilerIntegration.start();
570
Narayan Kamathc41638c2014-04-07 13:56:15 +0100571 boolean startSystemServer = false;
572 String socketName = "zygote";
573 String abiList = null;
574 for (int i = 1; i < argv.length; i++) {
575 if ("start-system-server".equals(argv[i])) {
576 startSystemServer = true;
577 } else if (argv[i].startsWith(ABI_LIST_ARG)) {
578 abiList = argv[i].substring(ABI_LIST_ARG.length());
579 } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
580 socketName = argv[i].substring(SOCKET_NAME_ARG.length());
581 } else {
582 throw new RuntimeException("Unknown command line argument: " + argv[i]);
583 }
584 }
585
586 if (abiList == null) {
587 throw new RuntimeException("No ABI list supplied.");
588 }
589
590 registerZygoteSocket(socketName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
592 SystemClock.uptimeMillis());
Jeff Brown0c2313d2011-06-10 22:46:40 -0700593 preload();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
595 SystemClock.uptimeMillis());
596
Brian Carlstrom17510862010-08-18 14:27:40 -0700597 // Finish profiling the zygote initialization.
598 SamplingProfilerIntegration.writeZygoteSnapshot();
Bob Leee5408332009-09-04 18:31:17 -0700599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 // Do an initial gc to clean up after startup
Mathieu Chartier9a88f102014-08-20 10:24:11 -0700601 gcAndFinalize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602
Jamie Gennis6ad04522013-04-15 18:53:24 -0700603 // Disable tracing so that forked processes do not inherit stale tracing tags from
604 // Zygote.
605 Trace.setTracingEnabled(false);
606
Narayan Kamathc41638c2014-04-07 13:56:15 +0100607 if (startSystemServer) {
Narayan Kamath64cd9072014-05-13 13:35:14 +0100608 startSystemServer(abiList, socketName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 }
610
611 Log.i(TAG, "Accepting command socket connections");
Narayan Kamathc41638c2014-04-07 13:56:15 +0100612 runSelectLoop(abiList);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613
614 closeServerSocket();
615 } catch (MethodAndArgsCaller caller) {
616 caller.run();
617 } catch (RuntimeException ex) {
618 Log.e(TAG, "Zygote died with exception", ex);
619 closeServerSocket();
620 throw ex;
621 }
622 }
623
624 /**
Narayan Kamath64cd9072014-05-13 13:35:14 +0100625 * Return {@code true} if this device configuration has another zygote.
626 *
627 * We determine this by comparing the device ABI list with this zygotes
628 * list. If this zygote supports all ABIs this device supports, there won't
629 * be another zygote.
630 */
631 private static boolean hasSecondZygote(String abiList) {
632 return !SystemProperties.get("ro.product.cpu.abilist").equals(abiList);
633 }
634
635 private static void waitForSecondaryZygote(String socketName) {
636 String otherZygoteName = Process.ZYGOTE_SOCKET.equals(socketName) ?
637 Process.SECONDARY_ZYGOTE_SOCKET : Process.ZYGOTE_SOCKET;
638 while (true) {
639 try {
640 final Process.ZygoteState zs = Process.ZygoteState.connect(otherZygoteName);
641 zs.close();
642 break;
643 } catch (IOException ioe) {
644 Log.w(TAG, "Got error connecting to zygote, retrying. msg= " + ioe.getMessage());
645 }
646
647 try {
648 Thread.sleep(1000);
649 } catch (InterruptedException ie) {
650 }
651 }
652 }
653
654 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 * Runs the zygote process's select loop. Accepts new connections as
656 * they happen, and reads commands from connections one spawn-request's
657 * worth at a time.
658 *
659 * @throws MethodAndArgsCaller in a child process when a main() should
660 * be executed.
661 */
Narayan Kamathc41638c2014-04-07 13:56:15 +0100662 private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
Nick Kralevichcae3d9f2013-01-30 09:51:40 -0800663 ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
664 ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665
666 fds.add(sServerSocket.getFileDescriptor());
667 peers.add(null);
668
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669 while (true) {
Elliott Hughes894724b2014-12-15 12:39:51 -0800670 StructPollfd[] pollFds = new StructPollfd[fds.size()];
671 for (int i = 0; i < pollFds.length; ++i) {
672 pollFds[i] = new StructPollfd();
673 pollFds[i].fd = fds.get(i);
674 pollFds[i].events = (short) POLLIN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 }
Elliott Hughes894724b2014-12-15 12:39:51 -0800676 try {
677 Os.poll(pollFds, -1);
678 } catch (ErrnoException ex) {
679 throw new RuntimeException("poll failed", ex);
680 }
681 for (int i = pollFds.length - 1; i >= 0; --i) {
682 if ((pollFds[i].revents & POLLIN) == 0) {
683 continue;
684 }
685 if (i == 0) {
686 ZygoteConnection newPeer = acceptCommandPeer(abiList);
687 peers.add(newPeer);
688 fds.add(newPeer.getFileDesciptor());
689 } else {
690 boolean done = peers.get(i).runOnce();
691 if (done) {
692 peers.remove(i);
693 fds.remove(i);
694 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 }
696 }
697 }
698 }
699
700 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 * Class not instantiable.
702 */
703 private ZygoteInit() {
704 }
705
706 /**
707 * Helper exception class which holds a method and arguments and
708 * can call them. This is used as part of a trampoline to get rid of
709 * the initial process setup stack frames.
710 */
711 public static class MethodAndArgsCaller extends Exception
712 implements Runnable {
713 /** method to call */
714 private final Method mMethod;
715
716 /** argument array */
717 private final String[] mArgs;
718
719 public MethodAndArgsCaller(Method method, String[] args) {
720 mMethod = method;
721 mArgs = args;
722 }
723
724 public void run() {
725 try {
726 mMethod.invoke(null, new Object[] { mArgs });
727 } catch (IllegalAccessException ex) {
728 throw new RuntimeException(ex);
729 } catch (InvocationTargetException ex) {
730 Throwable cause = ex.getCause();
731 if (cause instanceof RuntimeException) {
732 throw (RuntimeException) cause;
733 } else if (cause instanceof Error) {
734 throw (Error) cause;
735 }
736 throw new RuntimeException(ex);
737 }
738 }
739 }
740}