Merge "Refactored ZygoteConnection.Arguments to ZygoteArguments." am: 3a46c1b4ce

am: 3926f08109

Change-Id: I173c9cd671a9683793eee0c5053e3e8855ec0cf8
This commit is contained in:
Christian Wailes
2019-01-23 18:34:18 -08:00
committed by android-build-merger
5 changed files with 618 additions and 577 deletions

View File

@@ -16,13 +16,23 @@
package com.android.internal.os; package com.android.internal.os;
import static com.android.internal.os.ZygoteConnectionConstants.MAX_ZYGOTE_ARGC;
import android.net.Credentials;
import android.os.FactoryTest;
import android.os.IVold; import android.os.IVold;
import android.os.Process;
import android.os.SystemProperties;
import android.os.Trace; import android.os.Trace;
import android.system.ErrnoException; import android.system.ErrnoException;
import android.system.Os; import android.system.Os;
import android.util.Log;
import dalvik.system.ZygoteHooks; import dalvik.system.ZygoteHooks;
import java.io.BufferedReader;
import java.io.IOException;
/** @hide */ /** @hide */
public final class Zygote { public final class Zygote {
/* /*
@@ -91,6 +101,9 @@ public final class Zygote {
*/ */
public static final String CHILD_ZYGOTE_SOCKET_NAME_ARG = "--zygote-socket="; public static final String CHILD_ZYGOTE_SOCKET_NAME_ARG = "--zygote-socket=";
/** a prototype instance for a future List.toArray() */
protected static final int[][] INT_ARRAY_2D = new int[0][0];
private Zygote() {} private Zygote() {}
/** Called for some security initialization before any fork. */ /** Called for some security initialization before any fork. */
@@ -231,6 +244,147 @@ public final class Zygote {
private static native boolean nativeRemoveBlastulaTableEntry(int blastulaPID); private static native boolean nativeRemoveBlastulaTableEntry(int blastulaPID);
/**
* uid 1000 (Process.SYSTEM_UID) may specify any uid > 1000 in normal
* operation. It may also specify any gid and setgroups() list it chooses.
* In factory test mode, it may specify any UID.
*
* @param args non-null; zygote spawner arguments
* @param peer non-null; peer credentials
* @throws ZygoteSecurityException
*/
protected static void applyUidSecurityPolicy(ZygoteArguments args, Credentials peer)
throws ZygoteSecurityException {
if (peer.getUid() == Process.SYSTEM_UID) {
/* In normal operation, SYSTEM_UID can only specify a restricted
* set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
*/
boolean uidRestricted = FactoryTest.getMode() == FactoryTest.FACTORY_TEST_OFF;
if (uidRestricted && args.mUidSpecified && (args.mUid < Process.SYSTEM_UID)) {
throw new ZygoteSecurityException(
"System UID may not launch process with UID < "
+ Process.SYSTEM_UID);
}
}
// If not otherwise specified, uid and gid are inherited from peer
if (!args.mUidSpecified) {
args.mUid = peer.getUid();
args.mUidSpecified = true;
}
if (!args.mGidSpecified) {
args.mGid = peer.getGid();
args.mGidSpecified = true;
}
}
/**
* Applies debugger system properties to the zygote arguments.
*
* If "ro.debuggable" is "1", all apps are debuggable. Otherwise,
* the debugger state is specified via the "--enable-jdwp" flag
* in the spawn request.
*
* @param args non-null; zygote spawner args
*/
protected static void applyDebuggerSystemProperty(ZygoteArguments args) {
if (RoSystemProperties.DEBUGGABLE) {
args.mRuntimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
}
}
/**
* Applies zygote security policy.
* Based on the credentials of the process issuing a zygote command:
* <ol>
* <li> uid 0 (root) may specify --invoke-with to launch Zygote with a
* wrapper command.
* <li> Any other uid may not specify any invoke-with argument.
* </ul>
*
* @param args non-null; zygote spawner arguments
* @param peer non-null; peer credentials
* @throws ZygoteSecurityException
*/
protected static void applyInvokeWithSecurityPolicy(ZygoteArguments args, Credentials peer)
throws ZygoteSecurityException {
int peerUid = peer.getUid();
if (args.mInvokeWith != null && peerUid != 0
&& (args.mRuntimeFlags & Zygote.DEBUG_ENABLE_JDWP) == 0) {
throw new ZygoteSecurityException("Peer is permitted to specify an"
+ "explicit invoke-with wrapper command only for debuggable"
+ "applications.");
}
}
/**
* Applies invoke-with system properties to the zygote arguments.
*
* @param args non-null; zygote args
*/
protected static void applyInvokeWithSystemProperty(ZygoteArguments args) {
if (args.mInvokeWith == null && args.mNiceName != null) {
String property = "wrap." + args.mNiceName;
args.mInvokeWith = SystemProperties.get(property);
if (args.mInvokeWith != null && args.mInvokeWith.length() == 0) {
args.mInvokeWith = null;
}
}
}
/**
* Reads an argument list from the provided socket
* @return Argument list or null if EOF is reached
* @throws IOException passed straight through
*/
static String[] readArgumentList(BufferedReader socketReader) throws IOException {
/**
* See android.os.Process.zygoteSendArgsAndGetPid()
* Presently the wire format to the zygote process is:
* a) a count of arguments (argc, in essence)
* b) a number of newline-separated argument strings equal to count
*
* After the zygote process reads these it will write the pid of
* the child or -1 on failure.
*/
int argc;
try {
String argc_string = socketReader.readLine();
if (argc_string == null) {
// EOF reached.
return null;
}
argc = Integer.parseInt(argc_string);
} catch (NumberFormatException ex) {
Log.e("Zygote", "Invalid Zygote wire format: non-int at argc");
throw new IOException("Invalid wire format");
}
// See bug 1092107: large argc can be used for a DOS attack
if (argc > MAX_ZYGOTE_ARGC) {
throw new IOException("Max arg count exceeded");
}
String[] args = new String[argc];
for (int arg_index = 0; arg_index < argc; arg_index++) {
args[arg_index] = socketReader.readLine();
if (args[arg_index] == null) {
// We got an unexpected EOF.
throw new IOException("Truncated request");
}
}
return args;
}
private static void callPostForkSystemServerHooks() { private static void callPostForkSystemServerHooks() {
// SystemServer specific post fork hooks run before child post fork hooks. // SystemServer specific post fork hooks run before child post fork hooks.

View File

@@ -0,0 +1,390 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.os;
import java.util.ArrayList;
import java.util.Arrays;
/**
* Handles argument parsing for args related to the zygote spawner.
*
* Current recognized args:
* <ul>
* <li> --setuid=<i>uid of child process, defaults to 0</i>
* <li> --setgid=<i>gid of child process, defaults to 0</i>
* <li> --setgroups=<i>comma-separated list of supplimentary gid's</i>
* <li> --capabilities=<i>a pair of comma-separated integer strings
* indicating Linux capabilities(2) set for child. The first string represents the
* <code>permitted</code> set, and the second the
* <code>effective</code> set. Precede each with 0 or
* 0x for octal or hexidecimal value. If unspecified, both default to 0. This parameter is only
* applied if the uid of the new process will be non-0. </i>
* <li> --rlimit=r,c,m<i>tuple of values for setrlimit() call.
* <code>r</code> is the resource, <code>c</code> and <code>m</code>
* are the settings for current and max value.</i>
* <li> --instruction-set=<i>instruction-set-string</i> which instruction set to use/emulate.
* <li> --nice-name=<i>nice name to appear in ps</i>
* <li> --runtime-args indicates that the remaining arg list should
* be handed off to com.android.internal.os.RuntimeInit, rather than processed directly. Android
* runtime startup (eg, Binder initialization) is also eschewed.
* <li> [--] &lt;args for RuntimeInit &gt;
* </ul>
*/
class ZygoteArguments {
/**
* from --setuid
*/
int mUid = 0;
boolean mUidSpecified;
/**
* from --setgid
*/
int mGid = 0;
boolean mGidSpecified;
/**
* from --setgroups
*/
int[] mGids;
/**
* From --runtime-flags.
*/
int mRuntimeFlags;
/**
* From --mount-external
*/
int mMountExternal = Zygote.MOUNT_EXTERNAL_NONE;
/**
* from --target-sdk-version.
*/
int mTargetSdkVersion;
boolean mTargetSdkVersionSpecified;
/**
* from --nice-name
*/
String mNiceName;
/**
* from --capabilities
*/
boolean mCapabilitiesSpecified;
long mPermittedCapabilities;
long mEffectiveCapabilities;
/**
* from --seinfo
*/
boolean mSeInfoSpecified;
String mSeInfo;
/**
* from all --rlimit=r,c,m
*/
ArrayList<int[]> mRLimits;
/**
* from --invoke-with
*/
String mInvokeWith;
/**
* Any args after and including the first non-option arg (or after a '--')
*/
String[] mRemainingArgs;
/**
* Whether the current arguments constitute an ABI list query.
*/
boolean mAbiListQuery;
/**
* The instruction set to use, or null when not important.
*/
String mInstructionSet;
/**
* The app data directory. May be null, e.g., for the system server. Note that this might not be
* reliable in the case of process-sharing apps.
*/
String mAppDataDir;
/**
* The APK path of the package to preload, when using --preload-package.
*/
String mPreloadPackage;
/**
* The native library path of the package to preload, when using --preload-package.
*/
String mPreloadPackageLibs;
/**
* The filename of the native library to preload, when using --preload-package.
*/
String mPreloadPackageLibFileName;
/**
* The cache key under which to enter the preloaded package into the classloader cache, when
* using --preload-package.
*/
String mPreloadPackageCacheKey;
/**
* Whether this is a request to start preloading the default resources and classes. This
* argument only makes sense when the zygote is in lazy preload mode (i.e, when it's started
* with --enable-lazy-preload).
*/
boolean mPreloadDefault;
/**
* Whether this is a request to start a zygote process as a child of this zygote. Set with
* --start-child-zygote. The remaining arguments must include the CHILD_ZYGOTE_SOCKET_NAME_ARG
* flag to indicate the abstract socket name that should be used for communication.
*/
boolean mStartChildZygote;
/**
* Whether the current arguments constitute a request for the zygote's PID.
*/
boolean mPidQuery;
/**
* Exemptions from API blacklisting. These are sent to the pre-forked zygote at boot time, or
* when they change, via --set-api-blacklist-exemptions.
*/
String[] mApiBlacklistExemptions;
/**
* Sampling rate for logging hidden API accesses to the event log. This is sent to the
* pre-forked zygote at boot time, or when it changes, via --hidden-api-log-sampling-rate.
*/
int mHiddenApiAccessLogSampleRate = -1;
/**
* Constructs instance and parses args
*
* @param args zygote command-line args
*/
ZygoteArguments(String[] args) throws IllegalArgumentException {
parseArgs(args);
}
/**
* Parses the commandline arguments intended for the Zygote spawner (such as "--setuid=" and
* "--setgid=") and creates an array containing the remaining args.
*
* Per security review bug #1112214, duplicate args are disallowed in critical cases to make
* injection harder.
*/
private void parseArgs(String[] args)
throws IllegalArgumentException {
int curArg = 0;
boolean seenRuntimeArgs = false;
boolean expectRuntimeArgs = true;
for ( /* curArg */ ; curArg < args.length; curArg++) {
String arg = args[curArg];
if (arg.equals("--")) {
curArg++;
break;
} else if (arg.startsWith("--setuid=")) {
if (mUidSpecified) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
mUidSpecified = true;
mUid = Integer.parseInt(
arg.substring(arg.indexOf('=') + 1));
} else if (arg.startsWith("--setgid=")) {
if (mGidSpecified) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
mGidSpecified = true;
mGid = Integer.parseInt(
arg.substring(arg.indexOf('=') + 1));
} else if (arg.startsWith("--target-sdk-version=")) {
if (mTargetSdkVersionSpecified) {
throw new IllegalArgumentException(
"Duplicate target-sdk-version specified");
}
mTargetSdkVersionSpecified = true;
mTargetSdkVersion = Integer.parseInt(
arg.substring(arg.indexOf('=') + 1));
} else if (arg.equals("--runtime-args")) {
seenRuntimeArgs = true;
} else if (arg.startsWith("--runtime-flags=")) {
mRuntimeFlags = Integer.parseInt(
arg.substring(arg.indexOf('=') + 1));
} else if (arg.startsWith("--seinfo=")) {
if (mSeInfoSpecified) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
mSeInfoSpecified = true;
mSeInfo = arg.substring(arg.indexOf('=') + 1);
} else if (arg.startsWith("--capabilities=")) {
if (mCapabilitiesSpecified) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
mCapabilitiesSpecified = true;
String capString = arg.substring(arg.indexOf('=') + 1);
String[] capStrings = capString.split(",", 2);
if (capStrings.length == 1) {
mEffectiveCapabilities = Long.decode(capStrings[0]);
mPermittedCapabilities = mEffectiveCapabilities;
} else {
mPermittedCapabilities = Long.decode(capStrings[0]);
mEffectiveCapabilities = Long.decode(capStrings[1]);
}
} else if (arg.startsWith("--rlimit=")) {
// Duplicate --rlimit arguments are specifically allowed.
String[] limitStrings = arg.substring(arg.indexOf('=') + 1).split(",");
if (limitStrings.length != 3) {
throw new IllegalArgumentException(
"--rlimit= should have 3 comma-delimited ints");
}
int[] rlimitTuple = new int[limitStrings.length];
for (int i = 0; i < limitStrings.length; i++) {
rlimitTuple[i] = Integer.parseInt(limitStrings[i]);
}
if (mRLimits == null) {
mRLimits = new ArrayList();
}
mRLimits.add(rlimitTuple);
} else if (arg.startsWith("--setgroups=")) {
if (mGids != null) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
String[] params = arg.substring(arg.indexOf('=') + 1).split(",");
mGids = new int[params.length];
for (int i = params.length - 1; i >= 0; i--) {
mGids[i] = Integer.parseInt(params[i]);
}
} else if (arg.equals("--invoke-with")) {
if (mInvokeWith != null) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
try {
mInvokeWith = args[++curArg];
} catch (IndexOutOfBoundsException ex) {
throw new IllegalArgumentException(
"--invoke-with requires argument");
}
} else if (arg.startsWith("--nice-name=")) {
if (mNiceName != null) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
mNiceName = arg.substring(arg.indexOf('=') + 1);
} else if (arg.equals("--mount-external-default")) {
mMountExternal = Zygote.MOUNT_EXTERNAL_DEFAULT;
} else if (arg.equals("--mount-external-read")) {
mMountExternal = Zygote.MOUNT_EXTERNAL_READ;
} else if (arg.equals("--mount-external-write")) {
mMountExternal = Zygote.MOUNT_EXTERNAL_WRITE;
} else if (arg.equals("--query-abi-list")) {
mAbiListQuery = true;
} else if (arg.equals("--get-pid")) {
mPidQuery = true;
} else if (arg.startsWith("--instruction-set=")) {
mInstructionSet = arg.substring(arg.indexOf('=') + 1);
} else if (arg.startsWith("--app-data-dir=")) {
mAppDataDir = arg.substring(arg.indexOf('=') + 1);
} else if (arg.equals("--preload-package")) {
mPreloadPackage = args[++curArg];
mPreloadPackageLibs = args[++curArg];
mPreloadPackageLibFileName = args[++curArg];
mPreloadPackageCacheKey = args[++curArg];
} else if (arg.equals("--preload-default")) {
mPreloadDefault = true;
expectRuntimeArgs = false;
} else if (arg.equals("--start-child-zygote")) {
mStartChildZygote = true;
} else if (arg.equals("--set-api-blacklist-exemptions")) {
// consume all remaining args; this is a stand-alone command, never included
// with the regular fork command.
mApiBlacklistExemptions = Arrays.copyOfRange(args, curArg + 1, args.length);
curArg = args.length;
expectRuntimeArgs = false;
} else if (arg.startsWith("--hidden-api-log-sampling-rate=")) {
String rateStr = arg.substring(arg.indexOf('=') + 1);
try {
mHiddenApiAccessLogSampleRate = Integer.parseInt(rateStr);
} catch (NumberFormatException nfe) {
throw new IllegalArgumentException(
"Invalid log sampling rate: " + rateStr, nfe);
}
expectRuntimeArgs = false;
} else {
break;
}
}
if (mAbiListQuery || mPidQuery) {
if (args.length - curArg > 0) {
throw new IllegalArgumentException("Unexpected arguments after --query-abi-list.");
}
} else if (mPreloadPackage != null) {
if (args.length - curArg > 0) {
throw new IllegalArgumentException(
"Unexpected arguments after --preload-package.");
}
} else if (expectRuntimeArgs) {
if (!seenRuntimeArgs) {
throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
}
mRemainingArgs = new String[args.length - curArg];
System.arraycopy(args, curArg, mRemainingArgs, 0, mRemainingArgs.length);
}
if (mStartChildZygote) {
boolean seenChildSocketArg = false;
for (String arg : mRemainingArgs) {
if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
seenChildSocketArg = true;
break;
}
}
if (!seenChildSocketArg) {
throw new IllegalArgumentException("--start-child-zygote specified "
+ "without " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG);
}
}
}
}

View File

@@ -22,34 +22,31 @@ import static android.system.OsConstants.POLLIN;
import static android.system.OsConstants.STDERR_FILENO; import static android.system.OsConstants.STDERR_FILENO;
import static android.system.OsConstants.STDIN_FILENO; import static android.system.OsConstants.STDIN_FILENO;
import static android.system.OsConstants.STDOUT_FILENO; import static android.system.OsConstants.STDOUT_FILENO;
import static com.android.internal.os.ZygoteConnectionConstants.CONNECTION_TIMEOUT_MILLIS; import static com.android.internal.os.ZygoteConnectionConstants.CONNECTION_TIMEOUT_MILLIS;
import static com.android.internal.os.ZygoteConnectionConstants.MAX_ZYGOTE_ARGC;
import static com.android.internal.os.ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS; import static com.android.internal.os.ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
import android.net.Credentials; import android.net.Credentials;
import android.net.LocalSocket; import android.net.LocalSocket;
import android.os.FactoryTest;
import android.os.Process; import android.os.Process;
import android.os.SystemProperties;
import android.os.Trace; import android.os.Trace;
import android.system.ErrnoException; import android.system.ErrnoException;
import android.system.Os; import android.system.Os;
import android.system.StructPollfd; import android.system.StructPollfd;
import android.util.Log; import android.util.Log;
import dalvik.system.VMRuntime; import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import libcore.io.IoUtils;
/** /**
* A connection that can make spawn requests. * A connection that can make spawn requests.
@@ -57,9 +54,6 @@ import libcore.io.IoUtils;
class ZygoteConnection { class ZygoteConnection {
private static final String TAG = "Zygote"; private static final String TAG = "Zygote";
/** a prototype instance for a future List.toArray() */
private static final int[][] intArray2d = new int[0][0];
/** /**
* The command socket. * The command socket.
* *
@@ -108,7 +102,7 @@ class ZygoteConnection {
* *
* @return null-ok; file descriptor * @return null-ok; file descriptor
*/ */
FileDescriptor getFileDesciptor() { FileDescriptor getFileDescriptor() {
return mSocket.getFileDescriptor(); return mSocket.getFileDescriptor();
} }
@@ -122,11 +116,13 @@ class ZygoteConnection {
*/ */
Runnable processOneCommand(ZygoteServer zygoteServer) { Runnable processOneCommand(ZygoteServer zygoteServer) {
String args[]; String args[];
Arguments parsedArgs = null; ZygoteArguments parsedArgs = null;
FileDescriptor[] descriptors; FileDescriptor[] descriptors;
try { try {
args = readArgumentList(); args = Zygote.readArgumentList(mSocketReader);
// TODO (chriswailes): Remove this and add an assert.
descriptors = mSocket.getAncillaryFileDescriptors(); descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) { } catch (IOException ex) {
throw new IllegalStateException("IOException on command socket", ex); throw new IllegalStateException("IOException on command socket", ex);
@@ -143,60 +139,60 @@ class ZygoteConnection {
FileDescriptor childPipeFd = null; FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null; FileDescriptor serverPipeFd = null;
parsedArgs = new Arguments(args); parsedArgs = new ZygoteArguments(args);
if (parsedArgs.abiListQuery) { if (parsedArgs.mAbiListQuery) {
handleAbiListQuery(); handleAbiListQuery();
return null; return null;
} }
if (parsedArgs.pidQuery) { if (parsedArgs.mPidQuery) {
handlePidQuery(); handlePidQuery();
return null; return null;
} }
if (parsedArgs.preloadDefault) { if (parsedArgs.mPreloadDefault) {
handlePreload(); handlePreload();
return null; return null;
} }
if (parsedArgs.preloadPackage != null) { if (parsedArgs.mPreloadPackage != null) {
handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs, handlePreloadPackage(parsedArgs.mPreloadPackage, parsedArgs.mPreloadPackageLibs,
parsedArgs.preloadPackageLibFileName, parsedArgs.preloadPackageCacheKey); parsedArgs.mPreloadPackageLibFileName, parsedArgs.mPreloadPackageCacheKey);
return null; return null;
} }
if (parsedArgs.apiBlacklistExemptions != null) { if (parsedArgs.mApiBlacklistExemptions != null) {
handleApiBlacklistExemptions(parsedArgs.apiBlacklistExemptions); handleApiBlacklistExemptions(parsedArgs.mApiBlacklistExemptions);
return null; return null;
} }
if (parsedArgs.hiddenApiAccessLogSampleRate != -1) { if (parsedArgs.mHiddenApiAccessLogSampleRate != -1) {
handleHiddenApiAccessLogSampleRate(parsedArgs.hiddenApiAccessLogSampleRate); handleHiddenApiAccessLogSampleRate(parsedArgs.mHiddenApiAccessLogSampleRate);
return null; return null;
} }
if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) { if (parsedArgs.mPermittedCapabilities != 0 || parsedArgs.mEffectiveCapabilities != 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.mPermittedCapabilities)
", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities)); + ", effective=0x" + Long.toHexString(parsedArgs.mEffectiveCapabilities));
} }
applyUidSecurityPolicy(parsedArgs, peer); Zygote.applyUidSecurityPolicy(parsedArgs, peer);
applyInvokeWithSecurityPolicy(parsedArgs, peer); Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);
applyDebuggerSystemProperty(parsedArgs); Zygote.applyDebuggerSystemProperty(parsedArgs);
applyInvokeWithSystemProperty(parsedArgs); Zygote.applyInvokeWithSystemProperty(parsedArgs);
int[][] rlimits = null; int[][] rlimits = null;
if (parsedArgs.rlimits != null) { if (parsedArgs.mRLimits != null) {
rlimits = parsedArgs.rlimits.toArray(intArray2d); rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D);
} }
int[] fdsToIgnore = null; int[] fdsToIgnore = null;
if (parsedArgs.invokeWith != null) { if (parsedArgs.mInvokeWith != null) {
try { try {
FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC); FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
childPipeFd = pipeFds[1]; childPipeFd = pipeFds[1];
@@ -236,10 +232,10 @@ class ZygoteConnection {
fd = null; fd = null;
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote, parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
parsedArgs.instructionSet, parsedArgs.appDataDir); parsedArgs.mInstructionSet, parsedArgs.mAppDataDir);
try { try {
if (pid == 0) { if (pid == 0) {
@@ -251,7 +247,7 @@ class ZygoteConnection {
serverPipeFd = null; serverPipeFd = null;
return handleChildProc(parsedArgs, descriptors, childPipeFd, return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.startChildZygote); parsedArgs.mStartChildZygote);
} else { } else {
// In the parent. A pid < 0 indicates a failure and will be handled in // In the parent. A pid < 0 indicates a failure and will be handled in
// handleParentProc. // handleParentProc.
@@ -357,503 +353,6 @@ class ZygoteConnection {
return isEof; return isEof;
} }
/**
* Handles argument parsing for args related to the zygote spawner.
*
* Current recognized args:
* <ul>
* <li> --setuid=<i>uid of child process, defaults to 0</i>
* <li> --setgid=<i>gid of child process, defaults to 0</i>
* <li> --setgroups=<i>comma-separated list of supplimentary gid's</i>
* <li> --capabilities=<i>a pair of comma-separated integer strings
* indicating Linux capabilities(2) set for child. The first string
* represents the <code>permitted</code> set, and the second the
* <code>effective</code> set. Precede each with 0 or
* 0x for octal or hexidecimal value. If unspecified, both default to 0.
* This parameter is only applied if the uid of the new process will
* be non-0. </i>
* <li> --rlimit=r,c,m<i>tuple of values for setrlimit() call.
* <code>r</code> is the resource, <code>c</code> and <code>m</code>
* are the settings for current and max value.</i>
* <li> --instruction-set=<i>instruction-set-string</i> which instruction set to use/emulate.
* <li> --nice-name=<i>nice name to appear in ps</i>
* <li> --runtime-args indicates that the remaining arg list should
* be handed off to com.android.internal.os.RuntimeInit, rather than
* processed directly.
* Android runtime startup (eg, Binder initialization) is also eschewed.
* <li> [--] &lt;args for RuntimeInit &gt;
* </ul>
*/
static class Arguments {
/** from --setuid */
int uid = 0;
boolean uidSpecified;
/** from --setgid */
int gid = 0;
boolean gidSpecified;
/** from --setgroups */
int[] gids;
/**
* From --runtime-flags.
*/
int runtimeFlags;
/** From --mount-external */
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
/** from --target-sdk-version. */
int targetSdkVersion;
boolean targetSdkVersionSpecified;
/** from --nice-name */
String niceName;
/** from --capabilities */
boolean capabilitiesSpecified;
long permittedCapabilities;
long effectiveCapabilities;
/** from --seinfo */
boolean seInfoSpecified;
String seInfo;
/** from all --rlimit=r,c,m */
ArrayList<int[]> rlimits;
/** from --invoke-with */
String invokeWith;
/**
* Any args after and including the first non-option arg
* (or after a '--')
*/
String remainingArgs[];
/**
* Whether the current arguments constitute an ABI list query.
*/
boolean abiListQuery;
/**
* The instruction set to use, or null when not important.
*/
String instructionSet;
/**
* The app data directory. May be null, e.g., for the system server. Note that this might
* not be reliable in the case of process-sharing apps.
*/
String appDataDir;
/**
* The APK path of the package to preload, when using --preload-package.
*/
String preloadPackage;
/**
* The native library path of the package to preload, when using --preload-package.
*/
String preloadPackageLibs;
/**
* The filename of the native library to preload, when using --preload-package.
*/
String preloadPackageLibFileName;
/**
* The cache key under which to enter the preloaded package into the classloader cache,
* when using --preload-package.
*/
String preloadPackageCacheKey;
/**
* Whether this is a request to start preloading the default resources and classes.
* This argument only makes sense when the zygote is in lazy preload mode (i.e, when
* it's started with --enable-lazy-preload).
*/
boolean preloadDefault;
/**
* Whether this is a request to start a zygote process as a child of this zygote.
* Set with --start-child-zygote. The remaining arguments must include the
* CHILD_ZYGOTE_SOCKET_NAME_ARG flag to indicate the abstract socket name that
* should be used for communication.
*/
boolean startChildZygote;
/**
* Whether the current arguments constitute a request for the zygote's PID.
*/
boolean pidQuery;
/**
* Exemptions from API blacklisting. These are sent to the pre-forked zygote at boot time,
* or when they change, via --set-api-blacklist-exemptions.
*/
String[] apiBlacklistExemptions;
/**
* Sampling rate for logging hidden API accesses to the event log. This is sent to the
* pre-forked zygote at boot time, or when it changes, via --hidden-api-log-sampling-rate.
*/
int hiddenApiAccessLogSampleRate = -1;
/**
* Constructs instance and parses args
* @param args zygote command-line args
* @throws IllegalArgumentException
*/
Arguments(String args[]) throws IllegalArgumentException {
parseArgs(args);
}
/**
* Parses the commandline arguments intended for the Zygote spawner
* (such as "--setuid=" and "--setgid=") and creates an array
* containing the remaining args.
*
* Per security review bug #1112214, duplicate args are disallowed in
* critical cases to make injection harder.
*/
private void parseArgs(String args[])
throws IllegalArgumentException {
int curArg = 0;
boolean seenRuntimeArgs = false;
boolean expectRuntimeArgs = true;
for ( /* curArg */ ; curArg < args.length; curArg++) {
String arg = args[curArg];
if (arg.equals("--")) {
curArg++;
break;
} else if (arg.startsWith("--setuid=")) {
if (uidSpecified) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
uidSpecified = true;
uid = Integer.parseInt(
arg.substring(arg.indexOf('=') + 1));
} else if (arg.startsWith("--setgid=")) {
if (gidSpecified) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
gidSpecified = true;
gid = Integer.parseInt(
arg.substring(arg.indexOf('=') + 1));
} else if (arg.startsWith("--target-sdk-version=")) {
if (targetSdkVersionSpecified) {
throw new IllegalArgumentException(
"Duplicate target-sdk-version specified");
}
targetSdkVersionSpecified = true;
targetSdkVersion = Integer.parseInt(
arg.substring(arg.indexOf('=') + 1));
} else if (arg.equals("--runtime-args")) {
seenRuntimeArgs = true;
} else if (arg.startsWith("--runtime-flags=")) {
runtimeFlags = Integer.parseInt(
arg.substring(arg.indexOf('=') + 1));
} else if (arg.startsWith("--seinfo=")) {
if (seInfoSpecified) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
seInfoSpecified = true;
seInfo = arg.substring(arg.indexOf('=') + 1);
} else if (arg.startsWith("--capabilities=")) {
if (capabilitiesSpecified) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
capabilitiesSpecified = true;
String capString = arg.substring(arg.indexOf('=')+1);
String[] capStrings = capString.split(",", 2);
if (capStrings.length == 1) {
effectiveCapabilities = Long.decode(capStrings[0]);
permittedCapabilities = effectiveCapabilities;
} else {
permittedCapabilities = Long.decode(capStrings[0]);
effectiveCapabilities = Long.decode(capStrings[1]);
}
} else if (arg.startsWith("--rlimit=")) {
// Duplicate --rlimit arguments are specifically allowed.
String[] limitStrings
= arg.substring(arg.indexOf('=')+1).split(",");
if (limitStrings.length != 3) {
throw new IllegalArgumentException(
"--rlimit= should have 3 comma-delimited ints");
}
int[] rlimitTuple = new int[limitStrings.length];
for(int i=0; i < limitStrings.length; i++) {
rlimitTuple[i] = Integer.parseInt(limitStrings[i]);
}
if (rlimits == null) {
rlimits = new ArrayList();
}
rlimits.add(rlimitTuple);
} else if (arg.startsWith("--setgroups=")) {
if (gids != null) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
String[] params
= arg.substring(arg.indexOf('=') + 1).split(",");
gids = new int[params.length];
for (int i = params.length - 1; i >= 0 ; i--) {
gids[i] = Integer.parseInt(params[i]);
}
} else if (arg.equals("--invoke-with")) {
if (invokeWith != null) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
try {
invokeWith = args[++curArg];
} catch (IndexOutOfBoundsException ex) {
throw new IllegalArgumentException(
"--invoke-with requires argument");
}
} else if (arg.startsWith("--nice-name=")) {
if (niceName != null) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
niceName = arg.substring(arg.indexOf('=') + 1);
} else if (arg.equals("--mount-external-default")) {
mountExternal = Zygote.MOUNT_EXTERNAL_DEFAULT;
} else if (arg.equals("--mount-external-read")) {
mountExternal = Zygote.MOUNT_EXTERNAL_READ;
} else if (arg.equals("--mount-external-write")) {
mountExternal = Zygote.MOUNT_EXTERNAL_WRITE;
} else if (arg.equals("--query-abi-list")) {
abiListQuery = true;
} else if (arg.equals("--get-pid")) {
pidQuery = true;
} else if (arg.startsWith("--instruction-set=")) {
instructionSet = arg.substring(arg.indexOf('=') + 1);
} else if (arg.startsWith("--app-data-dir=")) {
appDataDir = arg.substring(arg.indexOf('=') + 1);
} else if (arg.equals("--preload-package")) {
preloadPackage = args[++curArg];
preloadPackageLibs = args[++curArg];
preloadPackageLibFileName = args[++curArg];
preloadPackageCacheKey = args[++curArg];
} else if (arg.equals("--preload-default")) {
preloadDefault = true;
expectRuntimeArgs = false;
} else if (arg.equals("--start-child-zygote")) {
startChildZygote = true;
} else if (arg.equals("--set-api-blacklist-exemptions")) {
// consume all remaining args; this is a stand-alone command, never included
// with the regular fork command.
apiBlacklistExemptions = Arrays.copyOfRange(args, curArg + 1, args.length);
curArg = args.length;
expectRuntimeArgs = false;
} else if (arg.startsWith("--hidden-api-log-sampling-rate=")) {
String rateStr = arg.substring(arg.indexOf('=') + 1);
try {
hiddenApiAccessLogSampleRate = Integer.parseInt(rateStr);
} catch (NumberFormatException nfe) {
throw new IllegalArgumentException(
"Invalid log sampling rate: " + rateStr, nfe);
}
expectRuntimeArgs = false;
} else {
break;
}
}
if (abiListQuery || pidQuery) {
if (args.length - curArg > 0) {
throw new IllegalArgumentException("Unexpected arguments after --query-abi-list.");
}
} else if (preloadPackage != null) {
if (args.length - curArg > 0) {
throw new IllegalArgumentException(
"Unexpected arguments after --preload-package.");
}
} else if (expectRuntimeArgs) {
if (!seenRuntimeArgs) {
throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
}
remainingArgs = new String[args.length - curArg];
System.arraycopy(args, curArg, remainingArgs, 0, remainingArgs.length);
}
if (startChildZygote) {
boolean seenChildSocketArg = false;
for (String arg : remainingArgs) {
if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
seenChildSocketArg = true;
break;
}
}
if (!seenChildSocketArg) {
throw new IllegalArgumentException("--start-child-zygote specified " +
"without " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG);
}
}
}
}
/**
* Reads an argument list from the command socket/
* @return Argument list or null if EOF is reached
* @throws IOException passed straight through
*/
private String[] readArgumentList()
throws IOException {
/**
* See android.os.Process.zygoteSendArgsAndGetPid()
* Presently the wire format to the zygote process is:
* a) a count of arguments (argc, in essence)
* b) a number of newline-separated argument strings equal to count
*
* After the zygote process reads these it will write the pid of
* the child or -1 on failure.
*/
int argc;
try {
String s = mSocketReader.readLine();
if (s == null) {
// EOF reached.
return null;
}
argc = Integer.parseInt(s);
} catch (NumberFormatException ex) {
Log.e(TAG, "invalid Zygote wire format: non-int at argc");
throw new IOException("invalid wire format");
}
// See bug 1092107: large argc can be used for a DOS attack
if (argc > MAX_ZYGOTE_ARGC) {
throw new IOException("max arg count exceeded");
}
String[] result = new String[argc];
for (int i = 0; i < argc; i++) {
result[i] = mSocketReader.readLine();
if (result[i] == null) {
// We got an unexpected EOF.
throw new IOException("truncated request");
}
}
return result;
}
/**
* uid 1000 (Process.SYSTEM_UID) may specify any uid &gt; 1000 in normal
* operation. It may also specify any gid and setgroups() list it chooses.
* In factory test mode, it may specify any UID.
*
* @param args non-null; zygote spawner arguments
* @param peer non-null; peer credentials
* @throws ZygoteSecurityException
*/
private static void applyUidSecurityPolicy(Arguments args, Credentials peer)
throws ZygoteSecurityException {
if (peer.getUid() == Process.SYSTEM_UID) {
/* In normal operation, SYSTEM_UID can only specify a restricted
* set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
*/
boolean uidRestricted = FactoryTest.getMode() == FactoryTest.FACTORY_TEST_OFF;
if (uidRestricted && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) {
throw new ZygoteSecurityException(
"System UID may not launch process with UID < "
+ Process.SYSTEM_UID);
}
}
// If not otherwise specified, uid and gid are inherited from peer
if (!args.uidSpecified) {
args.uid = peer.getUid();
args.uidSpecified = true;
}
if (!args.gidSpecified) {
args.gid = peer.getGid();
args.gidSpecified = true;
}
}
/**
* Applies debugger system properties to the zygote arguments.
*
* If "ro.debuggable" is "1", all apps are debuggable. Otherwise,
* the debugger state is specified via the "--enable-jdwp" flag
* in the spawn request.
*
* @param args non-null; zygote spawner args
*/
public static void applyDebuggerSystemProperty(Arguments args) {
if (RoSystemProperties.DEBUGGABLE) {
args.runtimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
}
}
/**
* Applies zygote security policy.
* Based on the credentials of the process issuing a zygote command:
* <ol>
* <li> uid 0 (root) may specify --invoke-with to launch Zygote with a
* wrapper command.
* <li> Any other uid may not specify any invoke-with argument.
* </ul>
*
* @param args non-null; zygote spawner arguments
* @param peer non-null; peer credentials
* @throws ZygoteSecurityException
*/
private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer)
throws ZygoteSecurityException {
int peerUid = peer.getUid();
if (args.invokeWith != null && peerUid != 0 &&
(args.runtimeFlags & Zygote.DEBUG_ENABLE_JDWP) == 0) {
throw new ZygoteSecurityException("Peer is permitted to specify an"
+ "explicit invoke-with wrapper command only for debuggable"
+ "applications.");
}
}
/**
* Applies invoke-with system properties to the zygote arguments.
*
* @param args non-null; zygote args
*/
public static void applyInvokeWithSystemProperty(Arguments args) {
if (args.invokeWith == null && args.niceName != null) {
String property = "wrap." + args.niceName;
args.invokeWith = SystemProperties.get(property);
if (args.invokeWith != null && args.invokeWith.length() == 0) {
args.invokeWith = null;
}
}
}
/** /**
* Handles post-fork setup of child proc, closing sockets as appropriate, * Handles post-fork setup of child proc, closing sockets as appropriate,
* reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
@@ -864,7 +363,7 @@ class ZygoteConnection {
* @param pipeFd null-ok; pipe for communication back to Zygote. * @param pipeFd null-ok; pipe for communication back to Zygote.
* @param isZygote whether this new child process is itself a new Zygote. * @param isZygote whether this new child process is itself a new Zygote.
*/ */
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd, boolean isZygote) { FileDescriptor pipeFd, boolean isZygote) {
/** /**
* By the time we get here, the native code has closed the two actual Zygote * By the time we get here, the native code has closed the two actual Zygote
@@ -887,27 +386,27 @@ class ZygoteConnection {
} }
} }
if (parsedArgs.niceName != null) { if (parsedArgs.mNiceName != null) {
Process.setArgV0(parsedArgs.niceName); Process.setArgV0(parsedArgs.mNiceName);
} }
// End of the postFork event. // End of the postFork event.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (parsedArgs.invokeWith != null) { if (parsedArgs.mInvokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith, WrapperInit.execApplication(parsedArgs.mInvokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion, parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
VMRuntime.getCurrentInstructionSet(), VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs); pipeFd, parsedArgs.mRemainingArgs);
// Should not get here. // Should not get here.
throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned"); throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
} else { } else {
if (!isZygote) { if (!isZygote) {
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
null /* classLoader */); parsedArgs.mRemainingArgs, null /* classLoader */);
} else { } else {
return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion, return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */); parsedArgs.mRemainingArgs, null /* classLoader */);
} }
} }
} }

View File

@@ -73,8 +73,7 @@ import java.security.Security;
* Pre-initializes some classes, and then waits for commands on a UNIX domain socket. Based on these * Pre-initializes some classes, and then waits for commands on a UNIX domain socket. Based on these
* commands, forks off child processes that inherit the initial state of the VM. * commands, forks off child processes that inherit the initial state of the VM.
* *
* Please see {@link ZygoteConnection.Arguments} for documentation on the * Please see {@link ZygoteArguments} for documentation on the client protocol.
* client protocol.
* *
* @hide * @hide
*/ */
@@ -434,12 +433,12 @@ public class ZygoteInit {
/** /**
* Finish remaining work for the newly forked system server process. * Finish remaining work for the newly forked system server process.
*/ */
private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) { private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
// set umask to 0077 so new files and directories will default to owner-only permissions. // set umask to 0077 so new files and directories will default to owner-only permissions.
Os.umask(S_IRWXG | S_IRWXO); Os.umask(S_IRWXG | S_IRWXO);
if (parsedArgs.niceName != null) { if (parsedArgs.mNiceName != null) {
Process.setArgV0(parsedArgs.niceName); Process.setArgV0(parsedArgs.mNiceName);
} }
final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH"); final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
@@ -458,8 +457,8 @@ public class ZygoteInit {
} }
} }
if (parsedArgs.invokeWith != null) { if (parsedArgs.mInvokeWith != null) {
String[] args = parsedArgs.remainingArgs; String[] args = parsedArgs.mRemainingArgs;
// If we have a non-null system server class path, we'll have to duplicate the // If we have a non-null system server class path, we'll have to duplicate the
// existing arguments and append the classpath to it. ART will handle the classpath // existing arguments and append the classpath to it. ART will handle the classpath
// correctly when we exec a new process. // correctly when we exec a new process.
@@ -471,15 +470,15 @@ public class ZygoteInit {
args = amendedArgs; args = amendedArgs;
} }
WrapperInit.execApplication(parsedArgs.invokeWith, WrapperInit.execApplication(parsedArgs.mInvokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion, parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
VMRuntime.getCurrentInstructionSet(), null, args); VMRuntime.getCurrentInstructionSet(), null, args);
throw new IllegalStateException("Unexpected return from WrapperInit.execApplication"); throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
} else { } else {
ClassLoader cl = null; ClassLoader cl = null;
if (systemServerClasspath != null) { if (systemServerClasspath != null) {
cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion); cl = createPathClassLoader(systemServerClasspath, parsedArgs.mTargetSdkVersion);
Thread.currentThread().setContextClassLoader(cl); Thread.currentThread().setContextClassLoader(cl);
} }
@@ -487,8 +486,8 @@ public class ZygoteInit {
/* /*
* Pass the remaining arguments to SystemServer. * Pass the remaining arguments to SystemServer.
*/ */
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.remainingArgs, cl); parsedArgs.mRemainingArgs, cl);
} }
/* should never reach here */ /* should never reach here */
@@ -683,29 +682,29 @@ public class ZygoteInit {
"--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT, "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
"com.android.server.SystemServer", "com.android.server.SystemServer",
}; };
ZygoteConnection.Arguments parsedArgs = null; ZygoteArguments parsedArgs = null;
int pid; int pid;
try { try {
parsedArgs = new ZygoteConnection.Arguments(args); parsedArgs = new ZygoteArguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs); Zygote.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs); Zygote.applyInvokeWithSystemProperty(parsedArgs);
boolean profileSystemServer = SystemProperties.getBoolean( boolean profileSystemServer = SystemProperties.getBoolean(
"dalvik.vm.profilesystemserver", false); "dalvik.vm.profilesystemserver", false);
if (profileSystemServer) { if (profileSystemServer) {
parsedArgs.runtimeFlags |= Zygote.PROFILE_SYSTEM_SERVER; parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
} }
/* Request to fork the system server process */ /* Request to fork the system server process */
pid = Zygote.forkSystemServer( pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid, parsedArgs.mUid, parsedArgs.mGid,
parsedArgs.gids, parsedArgs.mGids,
parsedArgs.runtimeFlags, parsedArgs.mRuntimeFlags,
null, null,
parsedArgs.permittedCapabilities, parsedArgs.mPermittedCapabilities,
parsedArgs.effectiveCapabilities); parsedArgs.mEffectiveCapabilities);
} catch (IllegalArgumentException ex) { } catch (IllegalArgumentException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }

View File

@@ -20,14 +20,14 @@ import static android.system.OsConstants.POLLIN;
import android.net.LocalServerSocket; import android.net.LocalServerSocket;
import android.net.LocalSocket; import android.net.LocalSocket;
import android.system.Os;
import android.system.ErrnoException; import android.system.ErrnoException;
import android.system.Os;
import android.system.StructPollfd; import android.system.StructPollfd;
import android.util.Log; import android.util.Log;
import android.util.Slog; import android.util.Slog;
import java.io.IOException;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
/** /**
@@ -63,8 +63,7 @@ class ZygoteServer {
*/ */
private boolean mIsForkChild; private boolean mIsForkChild;
ZygoteServer() { ZygoteServer() { }
}
void setForkChild() { void setForkChild() {
mIsForkChild = true; mIsForkChild = true;
@@ -197,7 +196,7 @@ class ZygoteServer {
if (i == 0) { if (i == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList); ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer); peers.add(newPeer);
fds.add(newPeer.getFileDesciptor()); fds.add(newPeer.getFileDescriptor());
} else { } else {
try { try {
ZygoteConnection connection = peers.get(i); ZygoteConnection connection = peers.get(i);