1. seandroid
  2. Untitled project
  3. frameworks/base

Commits

Stephen Smalley  committed 7f540f8 Merge

Merge branch 'master' into seandroid

  • Participants
  • Parent commits cec2239, dc97144
  • Branches seandroid

Comments (0)

Files changed (17)

File cmds/app_process/app_main.cpp

View file
 class AppRuntime : public AndroidRuntime
 {
 public:
-    AppRuntime()
-        : mParentDir(NULL)
+    AppRuntime(char* argBlockStart, const size_t argBlockLength)
+        : AndroidRuntime(argBlockStart, argBlockLength)
+        , mParentDir(NULL)
         , mClassName(NULL)
         , mClass(NULL)
         , mArgC(0)
 
 using namespace android;
 
-/*
- * sets argv0 to as much of newArgv0 as will fit
- */
-static void setArgv0(const char *argv0, const char *newArgv0)
-{
-    strlcpy(const_cast<char *>(argv0), newArgv0, strlen(argv0));
+static size_t computeArgBlockSize(int argc, char* const argv[]) {
+    // TODO: This assumes that all arguments are allocated in
+    // contiguous memory. There isn't any documented guarantee
+    // that this is the case, but this is how the kernel does it
+    // (see fs/exec.c).
+    //
+    // Also note that this is a constant for "normal" android apps.
+    // Since they're forked from zygote, the size of their command line
+    // is the size of the zygote command line.
+    //
+    // We change the process name of the process by over-writing
+    // the start of the argument block (argv[0]) with the new name of
+    // the process, so we'd mysteriously start getting truncated process
+    // names if the zygote command line decreases in size.
+    uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]);
+    uintptr_t end = reinterpret_cast<uintptr_t>(argv[argc - 1]);
+    end += strlen(argv[argc - 1]);
+
+    return (end - start);
 }
 
 int main(int argc, char* const argv[])
 {
-    // These are global variables in ProcessState.cpp
-    mArgC = argc;
-    mArgV = argv;
-
-    mArgLen = 0;
-    for (int i=0; i<argc; i++) {
-        mArgLen += strlen(argv[i]) + 1;
-    }
-    mArgLen--;
-
-    AppRuntime runtime;
-    const char* argv0 = argv[0];
-
+    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
     // Process command line arguments
     // ignore argv[0]
     argc--;
     }
 
     if (niceName && *niceName) {
-        setArgv0(argv0, niceName);
+        runtime.setArgv0(niceName);
         set_process_name(niceName);
     }
 

File core/java/android/os/Process.java

View file
 
 package android.os;
 
-import android.net.LocalSocketAddress;
 import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
 import android.util.Log;
-import dalvik.system.Zygote;
+
+import com.android.internal.os.Zygote;
 
 import java.io.BufferedWriter;
 import java.io.DataInputStream;

File core/java/android/view/ViewRootImpl.java

View file
         mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(MSG_FLUSH_LAYER_UPDATES));
     }
 
-    public boolean attachFunctor(int functor) {
+    public boolean attachFunctor(long functor) {
         //noinspection SimplifiableIfStatement
         if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
             return mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
         return false;
     }
 
-    public void detachFunctor(int functor) {
+    public void detachFunctor(long functor) {
         if (mAttachInfo.mHardwareRenderer != null) {
             mAttachInfo.mHardwareRenderer.detachFunctor(functor);
         }

File core/java/android/widget/TextView.java

View file
                 final int width = mRight - mLeft;
                 final int padding = getCompoundPaddingLeft() + getCompoundPaddingRight();
                 final float dx = mLayout.getLineRight(0) - (width - padding);
-                canvas.translate(isLayoutRtl ? -dx : +dx, 0.0f);
+                canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
             }
 
             if (mMarquee != null && mMarquee.isRunning()) {
                 final float dx = -mMarquee.getScroll();
-                canvas.translate(isLayoutRtl ? -dx : +dx, 0.0f);
+                canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
             }
         }
 
         }
 
         if (mMarquee != null && mMarquee.shouldDrawGhost()) {
-            final int dx = (int) mMarquee.getGhostOffset();
-            canvas.translate(isLayoutRtl ? -dx : dx, 0.0f);
+            final float dx = mMarquee.getGhostOffset();
+            canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
             layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);
         }
 

File core/java/com/android/internal/app/ChooserActivity.java

View file
         Intent intent = getIntent();
         Parcelable targetParcelable = intent.getParcelableExtra(Intent.EXTRA_INTENT);
         if (!(targetParcelable instanceof Intent)) {
-            Log.w("ChooseActivity", "Target is not an intent: " + targetParcelable);
+            Log.w("ChooserActivity", "Target is not an intent: " + targetParcelable);
             finish();
+            super.onCreate(null);
             return;
         }
         Intent target = (Intent)targetParcelable;
             initialIntents = new Intent[pa.length];
             for (int i=0; i<pa.length; i++) {
                 if (!(pa[i] instanceof Intent)) {
-                    Log.w("ChooseActivity", "Initial intent #" + i
+                    Log.w("ChooserActivity", "Initial intent #" + i
                             + " not an Intent: " + pa[i]);
                     finish();
+                    super.onCreate(null);
                     return;
                 }
                 initialIntents[i] = (Intent)pa[i];

File core/java/com/android/internal/os/WrapperInit.java

View file
 import java.io.IOException;
 
 import libcore.io.IoUtils;
-import libcore.io.Libcore;
-
-import dalvik.system.Zygote;
 
 /**
  * Startup class for the wrapper process.
      * @param niceName The nice name for the application, or null if none.
      * @param targetSdkVersion The target SDK version for the app.
      * @param pipeFd The pipe to which the application's pid should be written, or null if none.
-     * @param args Arguments for {@link RuntimeInit.main}.
+     * @param args Arguments for {@link RuntimeInit#main}.
      */
     public static void execApplication(String invokeWith, String niceName,
             int targetSdkVersion, FileDescriptor pipeFd, String[] args) {

File core/java/com/android/internal/os/Zygote.java

View file
+/*
+ * Copyright (C) 2014 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 dalvik.system.ZygoteHooks;
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+
+/** @hide */
+public final class Zygote {
+    /*
+    * Bit values for "debugFlags" argument.  The definitions are duplicated
+    * in the native code.
+    */
+
+    /** enable debugging over JDWP */
+    public static final int DEBUG_ENABLE_DEBUGGER   = 1;
+    /** enable JNI checks */
+    public static final int DEBUG_ENABLE_CHECKJNI   = 1 << 1;
+    /** enable Java programming language "assert" statements */
+    public static final int DEBUG_ENABLE_ASSERT     = 1 << 2;
+    /** disable the JIT compiler */
+    public static final int DEBUG_ENABLE_SAFEMODE   = 1 << 3;
+    /** Enable logging of third-party JNI activity. */
+    public static final int DEBUG_ENABLE_JNI_LOGGING = 1 << 4;
+
+    /** No external storage should be mounted. */
+    public static final int MOUNT_EXTERNAL_NONE = 0;
+    /** Single-user external storage should be mounted. */
+    public static final int MOUNT_EXTERNAL_SINGLEUSER = 1;
+    /** Multi-user external storage should be mounted. */
+    public static final int MOUNT_EXTERNAL_MULTIUSER = 2;
+    /** All multi-user external storage should be mounted. */
+    public static final int MOUNT_EXTERNAL_MULTIUSER_ALL = 3;
+
+    private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();
+
+    private Zygote() {}
+
+    /**
+     * Forks a new VM instance.  The current VM must have been started
+     * with the -Xzygote flag. <b>NOTE: new instance keeps all
+     * root capabilities. The new process is expected to call capset()</b>.
+     *
+     * @param uid the UNIX uid that the new process should setuid() to after
+     * fork()ing and and before spawning any threads.
+     * @param gid the UNIX gid that the new process should setgid() to after
+     * fork()ing and and before spawning any threads.
+     * @param gids null-ok; a list of UNIX gids that the new process should
+     * setgroups() to after fork and before spawning any threads.
+     * @param debugFlags bit flags that enable debugging features.
+     * @param rlimits null-ok an array of rlimit tuples, with the second
+     * dimension having a length of 3 and representing
+     * (resource, rlim_cur, rlim_max). These are set via the posix
+     * setrlimit(2) call.
+     * @param seInfo null-ok a string specifying SELinux information for
+     * the new process.
+     * @param niceName null-ok a string specifying the process name.
+     * @param fdsToClose an array of ints, holding one or more POSIX
+     * file descriptor numbers that are to be closed by the child
+     * (and replaced by /dev/null) after forking.  An integer value
+     * of -1 in any entry in the array means "ignore this one".
+     *
+     * @return 0 if this is the child, pid of the child
+     * if this is the parent, or -1 on error.
+     */
+    public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
+          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose) {
+        VM_HOOKS.preFork();
+        int pid = nativeForkAndSpecialize(
+                  uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose);
+        VM_HOOKS.postForkCommon();
+        return pid;
+    }
+
+    native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int debugFlags,
+          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose);
+
+    /**
+     * Special method to start the system server process. In addition to the
+     * common actions performed in forkAndSpecialize, the pid of the child
+     * process is recorded such that the death of the child process will cause
+     * zygote to exit.
+     *
+     * @param uid the UNIX uid that the new process should setuid() to after
+     * fork()ing and and before spawning any threads.
+     * @param gid the UNIX gid that the new process should setgid() to after
+     * fork()ing and and before spawning any threads.
+     * @param gids null-ok; a list of UNIX gids that the new process should
+     * setgroups() to after fork and before spawning any threads.
+     * @param debugFlags bit flags that enable debugging features.
+     * @param rlimits null-ok an array of rlimit tuples, with the second
+     * dimension having a length of 3 and representing
+     * (resource, rlim_cur, rlim_max). These are set via the posix
+     * setrlimit(2) call.
+     * @param permittedCapabilities argument for setcap()
+     * @param effectiveCapabilities argument for setcap()
+     *
+     * @return 0 if this is the child, pid of the child
+     * if this is the parent, or -1 on error.
+     */
+    public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
+            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
+        VM_HOOKS.preFork();
+        int pid = nativeForkSystemServer(
+                uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
+        VM_HOOKS.postForkCommon();
+        return pid;
+    }
+
+    native private static int nativeForkSystemServer(int uid, int gid, int[] gids, int debugFlags,
+            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
+
+    private static void callPostForkChildHooks(int debugFlags) {
+        VM_HOOKS.postForkChild(debugFlags);
+    }
+
+
+    /**
+     * Executes "/system/bin/sh -c &lt;command&gt;" using the exec() system call.
+     * This method throws a runtime exception if exec() failed, otherwise, this
+     * method never returns.
+     *
+     * @param command The shell command to execute.
+     */
+    public static void execShell(String command) {
+        String[] args = { "/system/bin/sh", "-c", command };
+        try {
+            Libcore.os.execv(args[0], args);
+        } catch (ErrnoException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Appends quotes shell arguments to the specified string builder.
+     * The arguments are quoted using single-quotes, escaped if necessary,
+     * prefixed with a space, and appended to the command.
+     *
+     * @param command A string builder for the shell command being constructed.
+     * @param args An array of argument strings to be quoted and appended to the command.
+     * @see #execShell(String)
+     */
+    public static void appendQuotedShellArgs(StringBuilder command, String[] args) {
+        for (String arg : args) {
+            command.append(" '").append(arg.replace("'", "'\\''")).append("'");
+        }
+    }
+}

File core/java/com/android/internal/os/ZygoteConnection.java

View file
 import android.util.Log;
 
 import dalvik.system.PathClassLoader;
-import dalvik.system.Zygote;
 
 import java.io.BufferedReader;
 import java.io.DataInputStream;
     /**
      * Applies invoke-with system properties to the zygote arguments.
      *
-     * @param parsedArgs non-null; zygote args
+     * @param args non-null; zygote args
      */
     public static void applyInvokeWithSystemProperty(Arguments args) {
         if (args.invokeWith == null && args.niceName != null) {

File core/java/com/android/internal/os/ZygoteInit.java

View file
 import android.util.Log;
 
 import dalvik.system.VMRuntime;
-import dalvik.system.Zygote;
 
 import libcore.io.IoUtils;
 import libcore.io.Libcore;

File core/jni/Android.mk

View file
 	android_content_res_ObbScanner.cpp \
 	android_content_res_Configuration.cpp \
 	android_animation_PropertyValuesHolder.cpp \
-	com_android_internal_net_NetworkStatsFactory.cpp
+	com_android_internal_net_NetworkStatsFactory.cpp \
+	com_android_internal_os_Zygote.cpp
 
 LOCAL_C_INCLUDES += \
 	$(JNI_H_INCLUDE) \

File core/jni/AndroidRuntime.cpp

View file
 extern int register_android_animation_PropertyValuesHolder(JNIEnv *env);
 extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
 extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
+extern int register_com_android_internal_os_Zygote(JNIEnv *env);
 
 static AndroidRuntime* gCurRuntime = NULL;
 
 
 /*static*/ JavaVM* AndroidRuntime::mJavaVM = NULL;
 
-
-AndroidRuntime::AndroidRuntime() :
-        mExitWithoutCleanup(false)
+AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
+        mExitWithoutCleanup(false),
+        mArgBlockStart(argBlockStart),
+        mArgBlockLength(argBlockLength)
 {
     SkGraphics::Init();
     // this sets our preference for 16bit images during decode
     return jniRegisterNativeMethods(env, className, gMethods, numMethods);
 }
 
+void AndroidRuntime::setArgv0(const char* argv0) {
+    strlcpy(mArgBlockStart, argv0, mArgBlockLength);
+}
+
 status_t AndroidRuntime::callMain(const char* className,
     jclass clazz, int argc, const char* const argv[])
 {
     REG_JNI(register_android_net_wifi_WifiNative),
     REG_JNI(register_android_os_MemoryFile),
     REG_JNI(register_com_android_internal_os_ZygoteInit),
+    REG_JNI(register_com_android_internal_os_Zygote),
     REG_JNI(register_android_hardware_Camera),
     REG_JNI(register_android_hardware_camera2_CameraMetadata),
     REG_JNI(register_android_hardware_SensorManager),

File core/jni/android_util_Process.cpp

View file
 
 #include <utils/Log.h>
 #include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
+#include <cutils/process_name.h>
 #include <cutils/sched_policy.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
     }
 
     if (name8.size() > 0) {
-        ProcessState::self()->setArgV0(name8.string());
+        const char* procName = name8.string();
+        set_process_name(procName);
+        AndroidRuntime::getRuntime()->setArgv0(procName);
     }
 }
 

File core/jni/com_android_internal_os_Zygote.cpp

View file
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#include "android_runtime/AndroidRuntime.h"
+
+// sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
+#include <sys/mount.h>
+#include <linux/fs.h>
+
+#include <grp.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "cutils/fs.h"
+#include "cutils/multiuser.h"
+#include "cutils/sched_policy.h"
+#include "utils/String8.h"
+#include "JNIHelp.h"
+#include "ScopedLocalRef.h"
+#include "ScopedPrimitiveArray.h"
+#include "ScopedUtfChars.h"
+
+#if defined(HAVE_PRCTL)
+#include <sys/prctl.h>
+#endif
+
+#include <selinux/android.h>
+
+#if defined(__linux__)
+#include <sys/personality.h>
+#include <sys/utsname.h>
+#if defined(HAVE_ANDROID_OS)
+#include <sys/capability.h>
+#endif
+#endif
+
+namespace {
+
+using android::String8;
+
+static pid_t gSystemServerPid = 0;
+
+static const char kZygoteClassName[] = "com/android/internal/os/Zygote";
+static jclass gZygoteClass;
+static jmethodID gCallPostForkChildHooks;
+
+// Must match values in com.android.internal.os.Zygote.
+enum MountExternalKind {
+  MOUNT_EXTERNAL_NONE = 0,
+  MOUNT_EXTERNAL_SINGLEUSER = 1,
+  MOUNT_EXTERNAL_MULTIUSER = 2,
+  MOUNT_EXTERNAL_MULTIUSER_ALL = 3,
+};
+
+static void RuntimeAbort(JNIEnv* env) {
+  env->FatalError("RuntimeAbort");
+}
+
+// This signal handler is for zygote mode, since the zygote must reap its children
+static void SigChldHandler(int /*signal_number*/) {
+  pid_t pid;
+  int status;
+
+  while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+     // Log process-death status that we care about.  In general it is
+     // not safe to call LOG(...) from a signal handler because of
+     // possible reentrancy.  However, we know a priori that the
+     // current implementation of LOG() is safe to call from a SIGCHLD
+     // handler in the zygote process.  If the LOG() implementation
+     // changes its locking strategy or its use of syscalls within the
+     // lazy-init critical section, its use here may become unsafe.
+    if (WIFEXITED(status)) {
+      if (WEXITSTATUS(status)) {
+        ALOGI("Process %d exited cleanly (%d)", pid, WEXITSTATUS(status));
+      } else if (false) {
+        ALOGI("Process %d exited cleanly (%d)", pid, WEXITSTATUS(status));
+      }
+    } else if (WIFSIGNALED(status)) {
+      if (WTERMSIG(status) != SIGKILL) {
+        ALOGI("Process %d exited cleanly (%d)", pid, WTERMSIG(status));
+      } else if (false) {
+        ALOGI("Process %d exited cleanly (%d)", pid, WTERMSIG(status));
+      }
+#ifdef WCOREDUMP
+      if (WCOREDUMP(status)) {
+        ALOGI("Process %d dumped core.", pid);
+      }
+#endif /* ifdef WCOREDUMP */
+    }
+
+    // If the just-crashed process is the system_server, bring down zygote
+    // so that it is restarted by init and system server will be restarted
+    // from there.
+    if (pid == gSystemServerPid) {
+      ALOGE("Exit zygote because system server (%d) has terminated");
+      kill(getpid(), SIGKILL);
+    }
+  }
+
+  if (pid < 0) {
+    ALOGW("Zygote SIGCHLD error in waitpid: %d", errno);
+  }
+}
+
+// Configures the SIGCHLD handler for the zygote process. This is configured
+// very late, because earlier in the runtime we may fork() and exec()
+// other processes, and we want to waitpid() for those rather than
+// have them be harvested immediately.
+//
+// This ends up being called repeatedly before each fork(), but there's
+// no real harm in that.
+static void SetSigChldHandler() {
+  struct sigaction sa;
+  memset(&sa, 0, sizeof(sa));
+  sa.sa_handler = SigChldHandler;
+
+  int err = sigaction(SIGCHLD, &sa, NULL);
+  if (err < 0) {
+    ALOGW("Error setting SIGCHLD handler: %d", errno);
+  }
+}
+
+// Sets the SIGCHLD handler back to default behavior in zygote children.
+static void UnsetSigChldHandler() {
+  struct sigaction sa;
+  memset(&sa, 0, sizeof(sa));
+  sa.sa_handler = SIG_DFL;
+
+  int err = sigaction(SIGCHLD, &sa, NULL);
+  if (err < 0) {
+    ALOGW("Error unsetting SIGCHLD handler: %d", errno);
+  }
+}
+
+// Calls POSIX setgroups() using the int[] object as an argument.
+// A NULL argument is tolerated.
+static void SetGids(JNIEnv* env, jintArray javaGids) {
+  if (javaGids == NULL) {
+    return;
+  }
+
+  ScopedIntArrayRO gids(env, javaGids);
+  if (gids.get() == NULL) {
+      RuntimeAbort(env);
+  }
+  int rc = setgroups(gids.size(), reinterpret_cast<const gid_t*>(&gids[0]));
+  if (rc == -1) {
+    ALOGE("setgroups failed");
+    RuntimeAbort(env);
+  }
+}
+
+// Sets the resource limits via setrlimit(2) for the values in the
+// two-dimensional array of integers that's passed in. The second dimension
+// contains a tuple of length 3: (resource, rlim_cur, rlim_max). NULL is
+// treated as an empty array.
+static void SetRLimits(JNIEnv* env, jobjectArray javaRlimits) {
+  if (javaRlimits == NULL) {
+    return;
+  }
+
+  rlimit rlim;
+  memset(&rlim, 0, sizeof(rlim));
+
+  for (int i = 0; i < env->GetArrayLength(javaRlimits); ++i) {
+    ScopedLocalRef<jobject> javaRlimitObject(env, env->GetObjectArrayElement(javaRlimits, i));
+    ScopedIntArrayRO javaRlimit(env, reinterpret_cast<jintArray>(javaRlimitObject.get()));
+    if (javaRlimit.size() != 3) {
+      ALOGE("rlimits array must have a second dimension of size 3");
+      RuntimeAbort(env);
+    }
+
+    rlim.rlim_cur = javaRlimit[1];
+    rlim.rlim_max = javaRlimit[2];
+
+    int rc = setrlimit(javaRlimit[0], &rlim);
+    if (rc == -1) {
+      ALOGE("setrlimit(%d, {%d, %d}) failed", javaRlimit[0], rlim.rlim_cur, rlim.rlim_max);
+      RuntimeAbort(env);
+    }
+  }
+}
+
+#if defined(HAVE_ANDROID_OS)
+
+// The debug malloc library needs to know whether it's the zygote or a child.
+extern "C" int gMallocLeakZygoteChild;
+
+static void EnableKeepCapabilities(JNIEnv* env) {
+  int rc = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+  if (rc == -1) {
+    ALOGE("prctl(PR_SET_KEEPCAPS) failed");
+    RuntimeAbort(env);
+  }
+}
+
+static void DropCapabilitiesBoundingSet(JNIEnv* env) {
+  for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
+    int rc = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
+    if (rc == -1) {
+      if (errno == EINVAL) {
+        ALOGE("prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify "
+              "your kernel is compiled with file capabilities support");
+      } else {
+        ALOGE("prctl(PR_CAPBSET_DROP) failed");
+        RuntimeAbort(env);
+      }
+    }
+  }
+}
+
+static void SetCapabilities(JNIEnv* env, int64_t permitted, int64_t effective) {
+  __user_cap_header_struct capheader;
+  memset(&capheader, 0, sizeof(capheader));
+  capheader.version = _LINUX_CAPABILITY_VERSION_3;
+  capheader.pid = 0;
+
+  __user_cap_data_struct capdata[2];
+  memset(&capdata, 0, sizeof(capdata));
+  capdata[0].effective = effective;
+  capdata[1].effective = effective >> 32;
+  capdata[0].permitted = permitted;
+  capdata[1].permitted = permitted >> 32;
+
+  if (capset(&capheader, &capdata[0]) == -1) {
+    ALOGE("capset(%lld, %lld) failed", permitted, effective);
+    RuntimeAbort(env);
+  }
+}
+
+static void SetSchedulerPolicy(JNIEnv* env) {
+  errno = -set_sched_policy(0, SP_DEFAULT);
+  if (errno != 0) {
+    ALOGE("set_sched_policy(0, SP_DEFAULT) failed");
+    RuntimeAbort(env);
+  }
+}
+
+#else
+
+static int gMallocLeakZygoteChild = 0;
+
+static void EnableKeepCapabilities(JNIEnv*) {}
+static void DropCapabilitiesBoundingSet(JNIEnv*) {}
+static void SetCapabilities(JNIEnv*, int64_t, int64_t) {}
+static void SetSchedulerPolicy(JNIEnv*) {}
+
+#endif
+
+// Create a private mount namespace and bind mount appropriate emulated
+// storage for the given user.
+static bool MountEmulatedStorage(uid_t uid, jint mount_mode) {
+  if (mount_mode == MOUNT_EXTERNAL_NONE) {
+    return true;
+  }
+
+  // See storage config details at http://source.android.com/tech/storage/
+  userid_t user_id = multiuser_get_user_id(uid);
+
+  // Create a second private mount namespace for our process
+  if (unshare(CLONE_NEWNS) == -1) {
+      ALOGW("Failed to unshare(): %d", errno);
+      return false;
+  }
+
+  // Create bind mounts to expose external storage
+  if (mount_mode == MOUNT_EXTERNAL_MULTIUSER || mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
+    // These paths must already be created by init.rc
+    const char* source = getenv("EMULATED_STORAGE_SOURCE");
+    const char* target = getenv("EMULATED_STORAGE_TARGET");
+    const char* legacy = getenv("EXTERNAL_STORAGE");
+    if (source == NULL || target == NULL || legacy == NULL) {
+      ALOGW("Storage environment undefined; unable to provide external storage");
+      return false;
+    }
+
+    // Prepare source paths
+
+    // /mnt/shell/emulated/0
+    const String8 source_user(String8::format("%s/%d", source, user_id));
+    // /storage/emulated/0
+    const String8 target_user(String8::format("%s/%d", target, user_id));
+
+    if (fs_prepare_dir(source_user.string(), 0000, 0, 0) == -1
+        || fs_prepare_dir(target_user.string(), 0000, 0, 0) == -1) {
+      return false;
+    }
+
+    if (mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
+      // Mount entire external storage tree for all users
+      if (TEMP_FAILURE_RETRY(mount(source, target, NULL, MS_BIND, NULL)) == -1) {
+        ALOGW("Failed to mount %s to %s :%d", source, target, errno);
+        return false;
+      }
+    } else {
+      // Only mount user-specific external storage
+      if (TEMP_FAILURE_RETRY(
+              mount(source_user.string(), target_user.string(), NULL, MS_BIND, NULL)) == -1) {
+        ALOGW("Failed to mount %s to %s: %d", source_user.string(), target_user.string(), errno);
+        return false;
+      }
+    }
+
+    if (fs_prepare_dir(legacy, 0000, 0, 0) == -1) {
+        return false;
+    }
+
+    // Finally, mount user-specific path into place for legacy users
+    if (TEMP_FAILURE_RETRY(
+            mount(target_user.string(), legacy, NULL, MS_BIND | MS_REC, NULL)) == -1) {
+      ALOGW("Failed to mount %s to %s: %d", target_user.string(), legacy, errno);
+      return false;
+    }
+  } else {
+    ALOGW("Mount mode %d unsupported", mount_mode);
+    return false;
+  }
+
+  return true;
+}
+
+#if defined(__linux__)
+static bool NeedsNoRandomizeWorkaround() {
+#if !defined(__arm__)
+    return false;
+#else
+    int major;
+    int minor;
+    struct utsname uts;
+    if (uname(&uts) == -1) {
+        return false;
+    }
+
+    if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
+        return false;
+    }
+
+    // Kernels before 3.4.* need the workaround.
+    return (major < 3) || ((major == 3) && (minor < 4));
+#endif
+}
+#endif
+
+// Utility to close down the Zygote socket file descriptors while
+// the child is still running as root with Zygote's privileges.  Each
+// descriptor (if any) is closed via dup2(), replacing it with a valid
+// (open) descriptor to /dev/null.
+
+static void DetachDescriptors(JNIEnv* env, jintArray fdsToClose) {
+  if (!fdsToClose) {
+    return;
+  }
+  jsize count = env->GetArrayLength(fdsToClose);
+  jint *ar = env->GetIntArrayElements(fdsToClose, 0);
+  if (!ar) {
+      ALOGE("Bad fd array");
+      RuntimeAbort(env);
+  }
+  jsize i;
+  int devnull;
+  for (i = 0; i < count; i++) {
+    devnull = open("/dev/null", O_RDWR);
+    if (devnull < 0) {
+      ALOGE("Failed to open /dev/null");
+      RuntimeAbort(env);
+      continue;
+    }
+    ALOGV("Switching descriptor %d to /dev/null: %d", ar[i], errno);
+    if (dup2(devnull, ar[i]) < 0) {
+      ALOGE("Failed dup2() on descriptor %d", ar[i]);
+      RuntimeAbort(env);
+    }
+    close(devnull);
+  }
+}
+
+void SetThreadName(const char* thread_name) {
+  bool hasAt = false;
+  bool hasDot = false;
+  const char* s = thread_name;
+  while (*s) {
+    if (*s == '.') {
+      hasDot = true;
+    } else if (*s == '@') {
+      hasAt = true;
+    }
+    s++;
+  }
+  const int len = s - thread_name;
+  if (len < 15 || hasAt || !hasDot) {
+    s = thread_name;
+  } else {
+    s = thread_name + len - 15;
+  }
+  // pthread_setname_np fails rather than truncating long strings.
+  char buf[16];       // MAX_TASK_COMM_LEN=16 is hard-coded into bionic
+  strlcpy(buf, s, sizeof(buf)-1);
+  errno = pthread_setname_np(pthread_self(), buf);
+  if (errno != 0) {
+    ALOGW("Unable to set the name of current thread to '%s'", buf);
+  }
+}
+
+// Utility routine to fork zygote and specialize the child process.
+static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
+                                     jint debug_flags, jobjectArray javaRlimits,
+                                     jlong permittedCapabilities, jlong effectiveCapabilities,
+                                     jint mount_external,
+                                     jstring java_se_info, jstring java_se_name,
+                                     bool is_system_server, jintArray fdsToClose) {
+  SetSigChldHandler();
+
+  pid_t pid = fork();
+
+  if (pid == 0) {
+    // The child process.
+    gMallocLeakZygoteChild = 1;
+
+    // Clean up any descriptors which must be closed immediately
+    DetachDescriptors(env, fdsToClose);
+
+    // Keep capabilities across UID change, unless we're staying root.
+    if (uid != 0) {
+      EnableKeepCapabilities(env);
+    }
+
+    DropCapabilitiesBoundingSet(env);
+
+    if (!MountEmulatedStorage(uid, mount_external)) {
+      ALOGW("Failed to mount emulated storage: %d", errno);
+      if (errno == ENOTCONN || errno == EROFS) {
+        // When device is actively encrypting, we get ENOTCONN here
+        // since FUSE was mounted before the framework restarted.
+        // When encrypted device is booting, we get EROFS since
+        // FUSE hasn't been created yet by init.
+        // In either case, continue without external storage.
+      } else {
+        ALOGE("Cannot continue without emulated storage");
+        RuntimeAbort(env);
+      }
+    }
+
+    SetGids(env, javaGids);
+
+    SetRLimits(env, javaRlimits);
+
+    int rc = setresgid(gid, gid, gid);
+    if (rc == -1) {
+      ALOGE("setresgid(%d) failed", gid);
+      RuntimeAbort(env);
+    }
+
+    rc = setresuid(uid, uid, uid);
+    if (rc == -1) {
+      ALOGE("setresuid(%d) failed", uid);
+      RuntimeAbort(env);
+    }
+
+#if defined(__linux__)
+    if (NeedsNoRandomizeWorkaround()) {
+        // Work around ARM kernel ASLR lossage (http://b/5817320).
+        int old_personality = personality(0xffffffff);
+        int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
+        if (new_personality == -1) {
+            ALOGW("personality(%d) failed", new_personality);
+        }
+    }
+#endif
+
+    SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
+
+    SetSchedulerPolicy(env);
+
+#if defined(HAVE_ANDROID_OS)
+    {  // NOLINT(whitespace/braces)
+      const char* se_info_c_str = NULL;
+      ScopedUtfChars* se_info = NULL;
+      if (java_se_info != NULL) {
+          se_info = new ScopedUtfChars(env, java_se_info);
+          se_info_c_str = se_info->c_str();
+          if (se_info_c_str == NULL) {
+            ALOGE("se_info_c_str == NULL");
+            RuntimeAbort(env);
+          }
+      }
+      const char* se_name_c_str = NULL;
+      ScopedUtfChars* se_name = NULL;
+      if (java_se_name != NULL) {
+          se_name = new ScopedUtfChars(env, java_se_name);
+          se_name_c_str = se_name->c_str();
+          if (se_name_c_str == NULL) {
+            ALOGE("se_name_c_str == NULL");
+            RuntimeAbort(env);
+          }
+      }
+      rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
+      if (rc == -1) {
+        ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
+              is_system_server, se_info_c_str, se_name_c_str);
+        RuntimeAbort(env);
+      }
+
+      // Make it easier to debug audit logs by setting the main thread's name to the
+      // nice name rather than "app_process".
+      if (se_info_c_str == NULL && is_system_server) {
+        se_name_c_str = "system_server";
+      }
+      if (se_info_c_str != NULL) {
+        SetThreadName(se_name_c_str);
+      }
+
+      delete se_info;
+      delete se_name;
+    }
+#else
+    UNUSED(is_system_server);
+    UNUSED(java_se_info);
+    UNUSED(java_se_name);
+#endif
+
+    UnsetSigChldHandler();
+
+    env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags);
+    if (env->ExceptionCheck()) {
+      ALOGE("Error calling post fork hooks.");
+      RuntimeAbort(env);
+    }
+  } else if (pid > 0) {
+    // the parent process
+  }
+  return pid;
+}
+}  // anonymous namespace
+
+namespace android {
+
+static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
+        JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
+        jint debug_flags, jobjectArray rlimits,
+        jint mount_external, jstring se_info, jstring se_name,
+        jintArray fdsToClose) {
+    return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
+            rlimits, 0, 0, mount_external, se_info, se_name, false, fdsToClose);
+}
+
+static jint com_android_internal_os_Zygote_nativeForkSystemServer(
+        JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
+        jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities,
+        jlong effectiveCapabilities) {
+  pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
+                                      debug_flags, rlimits,
+                                      permittedCapabilities, effectiveCapabilities,
+                                      MOUNT_EXTERNAL_NONE, NULL, NULL, true, NULL);
+  if (pid > 0) {
+      // The zygote process checks whether the child process has died or not.
+      ALOGI("System server process %d has been created", pid);
+      gSystemServerPid = pid;
+      // There is a slight window that the system server process has crashed
+      // but it went unnoticed because we haven't published its pid yet. So
+      // we recheck here just to make sure that all is well.
+      int status;
+      if (waitpid(pid, &status, WNOHANG) == pid) {
+          ALOGE("System server process %d has died. Restarting Zygote!", pid);
+          RuntimeAbort(env);
+      }
+  }
+  return pid;
+}
+
+static JNINativeMethod gMethods[] = {
+    { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I)I",
+      (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
+    { "nativeForkSystemServer", "(II[II[[IJJ)I",
+      (void *) com_android_internal_os_Zygote_nativeForkSystemServer }
+};
+
+int register_com_android_internal_os_Zygote(JNIEnv* env) {
+  gZygoteClass = (jclass) env->NewGlobalRef(env->FindClass(kZygoteClassName));
+  if (gZygoteClass == NULL) {
+    RuntimeAbort(env);
+  }
+  gCallPostForkChildHooks = env->GetStaticMethodID(gZygoteClass, "callPostForkChildHooks", "(I)V");
+
+  return AndroidRuntime::registerNativeMethods(env, "com/android/internal/os/Zygote",
+      gMethods, NELEM(gMethods));
+}
+}  // namespace android
+

File include/android_runtime/AndroidRuntime.h

View file
 class AndroidRuntime
 {
 public:
-    AndroidRuntime();
+    AndroidRuntime(char* argBlockStart, size_t argBlockSize);
     virtual ~AndroidRuntime();
 
     enum StartMode {
         Tool,
     };
 
+    void setArgv0(const char* argv0);
+
     /**
      * Register a set of methods in the specified class.
      */
 
     Vector<JavaVMOption> mOptions;
     bool mExitWithoutCleanup;
+    char* const mArgBlockStart;
+    const size_t mArgBlockLength;
 
     /* JNI JavaVM pointer */
     static JavaVM* mJavaVM;

File libs/hwui/Snapshot.h

View file
      * Returns the current clip in local coordinates. The clip rect is
      * transformed by the inverse transform matrix.
      */
-    const Rect& getLocalClip();
+    ANDROID_API const Rect& getLocalClip();
 
     /**
      * Resets the clip to the specified rect.

File services/java/com/android/server/SystemServer.java

View file
 
 import com.android.internal.R;
 import com.android.internal.os.BinderInternal;
+import com.android.internal.os.Zygote;
 import com.android.internal.os.SamplingProfilerIntegration;
 import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.accounts.AccountManagerService;
 import com.android.server.wm.WindowManagerService;
 
 import dalvik.system.VMRuntime;
-import dalvik.system.Zygote;
 
 import java.io.File;
 import java.util.Timer;

File services/java/com/android/server/am/ActivityManagerService.java

View file
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.ProcessCpuTracker;
 import com.android.internal.os.TransferPipe;
+import com.android.internal.os.Zygote;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.MemInfoReader;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
-import dalvik.system.Zygote;
-
 import libcore.io.IoUtils;
 
 import org.xmlpull.v1.XmlPullParser;