am d4b64409: Merge "Make zygotes aware of their supported ABIs."
* commit 'd4b644092e8d2719d01ad297b080bd50b1fdf60d': Make zygotes aware of their supported ABIs.
This commit is contained in:
@@ -10,8 +10,9 @@
|
|||||||
#include <binder/IPCThreadState.h>
|
#include <binder/IPCThreadState.h>
|
||||||
#include <binder/ProcessState.h>
|
#include <binder/ProcessState.h>
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
#include <cutils/process_name.h>
|
|
||||||
#include <cutils/memory.h>
|
#include <cutils/memory.h>
|
||||||
|
#include <cutils/process_name.h>
|
||||||
|
#include <cutils/properties.h>
|
||||||
#include <cutils/trace.h>
|
#include <cutils/trace.h>
|
||||||
#include <android_runtime/AndroidRuntime.h>
|
#include <android_runtime/AndroidRuntime.h>
|
||||||
|
|
||||||
@@ -135,6 +136,12 @@ static size_t computeArgBlockSize(int argc, char* const argv[]) {
|
|||||||
return (end - start);
|
return (end - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(__LP64__)
|
||||||
|
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
|
||||||
|
#else
|
||||||
|
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
|
||||||
|
#endif
|
||||||
|
|
||||||
int main(int argc, char* const argv[])
|
int main(int argc, char* const argv[])
|
||||||
{
|
{
|
||||||
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
|
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
|
||||||
@@ -205,6 +212,17 @@ int main(int argc, char* const argv[])
|
|||||||
args.add(String8("start-system-server"));
|
args.add(String8("start-system-server"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char prop[PROP_VALUE_MAX];
|
||||||
|
if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
|
||||||
|
LOG_ALWAYS_FATAL("app_process: Unable to deterimine ABI list from property %s.",
|
||||||
|
ABI_LIST_PROPERTY);
|
||||||
|
return 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
String8 abiFlag("--abi-list=");
|
||||||
|
abiFlag.append(prop);
|
||||||
|
args.add(abiFlag);
|
||||||
|
|
||||||
// In zygote mode, pass all remaining arguments to the zygote
|
// In zygote mode, pass all remaining arguments to the zygote
|
||||||
// main() method.
|
// main() method.
|
||||||
for (; i < argc; ++i) {
|
for (; i < argc; ++i) {
|
||||||
|
|||||||
@@ -22,9 +22,7 @@ import android.os.Process;
|
|||||||
import android.os.SELinux;
|
import android.os.SELinux;
|
||||||
import android.os.SystemProperties;
|
import android.os.SystemProperties;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import dalvik.system.PathClassLoader;
|
import dalvik.system.PathClassLoader;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
@@ -34,8 +32,8 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import libcore.io.ErrnoException;
|
import libcore.io.ErrnoException;
|
||||||
import libcore.io.IoUtils;
|
import libcore.io.IoUtils;
|
||||||
import libcore.io.Libcore;
|
import libcore.io.Libcore;
|
||||||
@@ -59,7 +57,7 @@ class ZygoteConnection {
|
|||||||
private static final int CONNECTION_TIMEOUT_MILLIS = 1000;
|
private static final int CONNECTION_TIMEOUT_MILLIS = 1000;
|
||||||
|
|
||||||
/** max number of arguments that a connection can specify */
|
/** max number of arguments that a connection can specify */
|
||||||
private static final int MAX_ZYGOTE_ARGC=1024;
|
private static final int MAX_ZYGOTE_ARGC = 1024;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The command socket.
|
* The command socket.
|
||||||
@@ -73,15 +71,18 @@ class ZygoteConnection {
|
|||||||
private final BufferedReader mSocketReader;
|
private final BufferedReader mSocketReader;
|
||||||
private final Credentials peer;
|
private final Credentials peer;
|
||||||
private final String peerSecurityContext;
|
private final String peerSecurityContext;
|
||||||
|
private final String abiList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs instance from connected socket.
|
* Constructs instance from connected socket.
|
||||||
*
|
*
|
||||||
* @param socket non-null; connected socket
|
* @param socket non-null; connected socket
|
||||||
|
* @param abiList non-null; a list of ABIs this zygote supports.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
ZygoteConnection(LocalSocket socket) throws IOException {
|
ZygoteConnection(LocalSocket socket, String abiList) throws IOException {
|
||||||
mSocket = socket;
|
mSocket = socket;
|
||||||
|
this.abiList = abiList;
|
||||||
|
|
||||||
mSocketOutStream
|
mSocketOutStream
|
||||||
= new DataOutputStream(socket.getOutputStream());
|
= new DataOutputStream(socket.getOutputStream());
|
||||||
@@ -110,43 +111,6 @@ class ZygoteConnection {
|
|||||||
return mSocket.getFileDescriptor();
|
return mSocket.getFileDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads start commands from an open command socket.
|
|
||||||
* Start commands are presently a pair of newline-delimited lines
|
|
||||||
* indicating a) class to invoke main() on b) nice name to set argv[0] to.
|
|
||||||
* Continues to read commands and forkAndSpecialize children until
|
|
||||||
* the socket is closed. This method is used in ZYGOTE_FORK_MODE
|
|
||||||
*
|
|
||||||
* @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main()
|
|
||||||
* method in child process
|
|
||||||
*/
|
|
||||||
void run() throws ZygoteInit.MethodAndArgsCaller {
|
|
||||||
|
|
||||||
int loopCount = ZygoteInit.GC_LOOP_COUNT;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
/*
|
|
||||||
* Call gc() before we block in readArgumentList().
|
|
||||||
* It's work that has to be done anyway, and it's better
|
|
||||||
* to avoid making every child do it. It will also
|
|
||||||
* madvise() any free memory as a side-effect.
|
|
||||||
*
|
|
||||||
* Don't call it every time, because walking the entire
|
|
||||||
* heap is a lot of overhead to free a few hundred bytes.
|
|
||||||
*/
|
|
||||||
if (loopCount <= 0) {
|
|
||||||
ZygoteInit.gc();
|
|
||||||
loopCount = ZygoteInit.GC_LOOP_COUNT;
|
|
||||||
} else {
|
|
||||||
loopCount--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runOnce()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads one start command from the command socket. If successful,
|
* Reads one start command from the command socket. If successful,
|
||||||
* a child is forked and a {@link ZygoteInit.MethodAndArgsCaller}
|
* a child is forked and a {@link ZygoteInit.MethodAndArgsCaller}
|
||||||
@@ -196,6 +160,11 @@ class ZygoteConnection {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
parsedArgs = new Arguments(args);
|
parsedArgs = new Arguments(args);
|
||||||
|
|
||||||
|
if (parsedArgs.abiListQuery) {
|
||||||
|
return handleAbiListQuery();
|
||||||
|
}
|
||||||
|
|
||||||
if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
|
if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
|
||||||
throw new ZygoteSecurityException("Client may not specify capabilities: " +
|
throw new ZygoteSecurityException("Client may not specify capabilities: " +
|
||||||
"permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
|
"permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
|
||||||
@@ -287,6 +256,18 @@ class ZygoteConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean handleAbiListQuery() {
|
||||||
|
try {
|
||||||
|
final byte[] abiListBytes = abiList.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
mSocketOutStream.writeInt(abiListBytes.length);
|
||||||
|
mSocketOutStream.write(abiListBytes);
|
||||||
|
return false;
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Log.e(TAG, "Error writing to command socket", ioe);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes socket associated with this connection.
|
* Closes socket associated with this connection.
|
||||||
*/
|
*/
|
||||||
@@ -387,6 +368,11 @@ class ZygoteConnection {
|
|||||||
*/
|
*/
|
||||||
String remainingArgs[];
|
String remainingArgs[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the current arguments constitute an ABI list query.
|
||||||
|
*/
|
||||||
|
boolean abiListQuery;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs instance and parses args
|
* Constructs instance and parses args
|
||||||
* @param args zygote command-line args
|
* @param args zygote command-line args
|
||||||
@@ -540,6 +526,8 @@ class ZygoteConnection {
|
|||||||
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
|
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
|
||||||
} else if (arg.equals("--mount-external-multiuser-all")) {
|
} else if (arg.equals("--mount-external-multiuser-all")) {
|
||||||
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL;
|
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL;
|
||||||
|
} else if (arg.equals("--query-abi-list")) {
|
||||||
|
abiListQuery = true;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -975,7 +963,7 @@ class ZygoteConnection {
|
|||||||
mSocketOutStream.writeInt(pid);
|
mSocketOutStream.writeInt(pid);
|
||||||
mSocketOutStream.writeBoolean(usingWrapper);
|
mSocketOutStream.writeBoolean(usingWrapper);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
Log.e(TAG, "Error reading from command socket", ex);
|
Log.e(TAG, "Error writing to command socket", ex);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ public class ZygoteInit {
|
|||||||
|
|
||||||
private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
|
private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
|
||||||
|
|
||||||
private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";
|
private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
|
||||||
|
|
||||||
private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
|
private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
|
||||||
private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
|
private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
|
||||||
@@ -72,8 +72,9 @@ public class ZygoteInit {
|
|||||||
/** when preloading, GC after allocating this many bytes */
|
/** when preloading, GC after allocating this many bytes */
|
||||||
private static final int PRELOAD_GC_THRESHOLD = 50000;
|
private static final int PRELOAD_GC_THRESHOLD = 50000;
|
||||||
|
|
||||||
public static final String USAGE_STRING =
|
private static final String ABI_LIST_ARG = "--abi-list=";
|
||||||
" <\"start-system-server\"|\"\" for startSystemServer>";
|
|
||||||
|
private static final String SOCKET_NAME_ARG = "--socket-name=";
|
||||||
|
|
||||||
private static LocalServerSocket sServerSocket;
|
private static LocalServerSocket sServerSocket;
|
||||||
|
|
||||||
@@ -150,15 +151,15 @@ public class ZygoteInit {
|
|||||||
*
|
*
|
||||||
* @throws RuntimeException when open fails
|
* @throws RuntimeException when open fails
|
||||||
*/
|
*/
|
||||||
private static void registerZygoteSocket() {
|
private static void registerZygoteSocket(String socketName) {
|
||||||
if (sServerSocket == null) {
|
if (sServerSocket == null) {
|
||||||
int fileDesc;
|
int fileDesc;
|
||||||
|
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
|
||||||
try {
|
try {
|
||||||
String env = System.getenv(ANDROID_SOCKET_ENV);
|
String env = System.getenv(fullSocketName);
|
||||||
fileDesc = Integer.parseInt(env);
|
fileDesc = Integer.parseInt(env);
|
||||||
} catch (RuntimeException ex) {
|
} catch (RuntimeException ex) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
|
||||||
ANDROID_SOCKET_ENV + " unset or invalid", ex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -175,9 +176,9 @@ public class ZygoteInit {
|
|||||||
* Waits for and accepts a single command connection. Throws
|
* Waits for and accepts a single command connection. Throws
|
||||||
* RuntimeException on failure.
|
* RuntimeException on failure.
|
||||||
*/
|
*/
|
||||||
private static ZygoteConnection acceptCommandPeer() {
|
private static ZygoteConnection acceptCommandPeer(String abiList) {
|
||||||
try {
|
try {
|
||||||
return new ZygoteConnection(sServerSocket.accept());
|
return new ZygoteConnection(sServerSocket.accept(), abiList);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"IOException during accept()", ex);
|
"IOException during accept()", ex);
|
||||||
@@ -567,7 +568,26 @@ public class ZygoteInit {
|
|||||||
// Start profiling the zygote initialization.
|
// Start profiling the zygote initialization.
|
||||||
SamplingProfilerIntegration.start();
|
SamplingProfilerIntegration.start();
|
||||||
|
|
||||||
registerZygoteSocket();
|
boolean startSystemServer = false;
|
||||||
|
String socketName = "zygote";
|
||||||
|
String abiList = null;
|
||||||
|
for (int i = 1; i < argv.length; i++) {
|
||||||
|
if ("start-system-server".equals(argv[i])) {
|
||||||
|
startSystemServer = true;
|
||||||
|
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
|
||||||
|
abiList = argv[i].substring(ABI_LIST_ARG.length());
|
||||||
|
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
|
||||||
|
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Unknown command line argument: " + argv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abiList == null) {
|
||||||
|
throw new RuntimeException("No ABI list supplied.");
|
||||||
|
}
|
||||||
|
|
||||||
|
registerZygoteSocket(socketName);
|
||||||
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
|
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
|
||||||
SystemClock.uptimeMillis());
|
SystemClock.uptimeMillis());
|
||||||
preload();
|
preload();
|
||||||
@@ -584,20 +604,12 @@ public class ZygoteInit {
|
|||||||
// Zygote.
|
// Zygote.
|
||||||
Trace.setTracingEnabled(false);
|
Trace.setTracingEnabled(false);
|
||||||
|
|
||||||
// If requested, start system server directly from Zygote
|
if (startSystemServer) {
|
||||||
if (argv.length != 2) {
|
|
||||||
throw new RuntimeException(argv[0] + USAGE_STRING);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argv[1].equals("start-system-server")) {
|
|
||||||
startSystemServer();
|
startSystemServer();
|
||||||
} else if (!argv[1].equals("")) {
|
|
||||||
throw new RuntimeException(argv[0] + USAGE_STRING);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i(TAG, "Accepting command socket connections");
|
Log.i(TAG, "Accepting command socket connections");
|
||||||
|
runSelectLoop(abiList);
|
||||||
runSelectLoop();
|
|
||||||
|
|
||||||
closeServerSocket();
|
closeServerSocket();
|
||||||
} catch (MethodAndArgsCaller caller) {
|
} catch (MethodAndArgsCaller caller) {
|
||||||
@@ -617,7 +629,7 @@ public class ZygoteInit {
|
|||||||
* @throws MethodAndArgsCaller in a child process when a main() should
|
* @throws MethodAndArgsCaller in a child process when a main() should
|
||||||
* be executed.
|
* be executed.
|
||||||
*/
|
*/
|
||||||
private static void runSelectLoop() throws MethodAndArgsCaller {
|
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
|
||||||
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
|
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
|
||||||
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
|
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
|
||||||
FileDescriptor[] fdArray = new FileDescriptor[4];
|
FileDescriptor[] fdArray = new FileDescriptor[4];
|
||||||
@@ -656,7 +668,7 @@ public class ZygoteInit {
|
|||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
throw new RuntimeException("Error in select()");
|
throw new RuntimeException("Error in select()");
|
||||||
} else if (index == 0) {
|
} else if (index == 0) {
|
||||||
ZygoteConnection newPeer = acceptCommandPeer();
|
ZygoteConnection newPeer = acceptCommandPeer(abiList);
|
||||||
peers.add(newPeer);
|
peers.add(newPeer);
|
||||||
fds.add(newPeer.getFileDesciptor());
|
fds.add(newPeer.getFileDesciptor());
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user