Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d482d54 authored by Chris Wailes's avatar Chris Wailes
Browse files

Adds Zygote.initNativeState

This patch replaces three seperate native initialization functions with
a single function, reducing the number of times we need to cross the JNI
boundary.  In addition this loads an empty performance profile for the
zygote to address b/129704892.

Bug: 129704892
Test: make & boot
Test: Treehugger
Change-Id: I0413f554e0963a714e0b4de3196d31ffe6775a3a
parent 86b7528e
Loading
Loading
Loading
Loading
+8 −14
Original line number Diff line number Diff line
@@ -197,9 +197,6 @@ public final class Zygote {

    private Zygote() {}

    /** Called for some security initialization before any fork. */
    static native void nativeSecurityInit();

    /**
     * Forks a new VM instance.  The current VM must have been started
     * with the -Xzygote flag. <b>NOTE: new instance keeps all
@@ -384,22 +381,19 @@ public final class Zygote {
    native protected static void nativeInstallSeccompUidGidFilter(int uidGidMin, int uidGidMax);

    /**
     * Zygote unmount storage space on initializing.
     * This method is called once.
     */
    protected static native void nativeUnmountStorageOnInit();

    /**
     * Get socket file descriptors (opened by init) from the environment and
     * store them for access from native code later.
     * Initialize the native state of the Zygote.  This inclues
     *   - Fetching socket FDs from the environment
     *   - Initializing security properties
     *   - Unmounting storage as appropriate
     *   - Loading necessary performance profile information
     *
     * @param isPrimary  True if this is the zygote process, false if it is zygote_secondary
     */
    public static void getSocketFDs(boolean isPrimary) {
        nativeGetSocketFDs(isPrimary);
    static void initNativeState(boolean isPrimary) {
        nativeInitNativeState(isPrimary);
    }

    protected static native void nativeGetSocketFDs(boolean isPrimary);
    protected static native void nativeInitNativeState(boolean isPrimary);

    /**
     * Returns the raw string value of a system property.
+3 −7
Original line number Diff line number Diff line
@@ -20,10 +20,10 @@ import static android.system.OsConstants.S_IRWXG;
import static android.system.OsConstants.S_IRWXO;

import android.annotation.UnsupportedAppUsage;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.app.ApplicationLoaders;
import android.content.pm.SharedLibraryInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.Environment;
import android.os.IInstalld;
@@ -863,8 +863,6 @@ public class ZygoteInit {
                throw new RuntimeException("No ABI list supplied.");
            }

            Zygote.getSocketFDs(isPrimaryZygote);

            // In some configurations, we avoid preloading resources and classes eagerly.
            // In such cases, we will preload things prior to our first fork.
            if (!enableLazyPreload) {
@@ -889,10 +887,8 @@ public class ZygoteInit {
            // Zygote.
            Trace.setTracingEnabled(false, 0);

            Zygote.nativeSecurityInit();

            // Zygote process unmounts root storage spaces.
            Zygote.nativeUnmountStorageOnInit();
            Zygote.initNativeState(isPrimaryZygote);

            ZygoteHooks.stopZygoteNoThreadCreation();

+72 −56
Original line number Diff line number Diff line
@@ -126,7 +126,7 @@ static constexpr const char* kZygoteInitClassName = "com/android/internal/os/Zyg
static jclass gZygoteInitClass;
static jmethodID gCreateSystemServerClassLoader;

static bool g_is_security_enforced = true;
static bool gIsSecurityEnforced = true;

/**
 * The maximum number of characters (not including a null terminator) that a
@@ -510,7 +510,7 @@ static void PreApplicationInit() {
}

static void SetUpSeccompFilter(uid_t uid, bool is_child_zygote) {
  if (!g_is_security_enforced) {
  if (!gIsSecurityEnforced) {
    ALOGI("seccomp disabled by setenforce 0");
    return;
  }
@@ -1626,18 +1626,48 @@ std::vector<int> MakeUsapPipeReadFDVector() {
  return fd_vec;
}

}  // anonymous namespace
static void UnmountStorageOnInit(JNIEnv* env) {
  // Zygote process unmount root storage space initially before every child processes are forked.
  // Every forked child processes (include SystemServer) only mount their own root storage space
  // and no need unmount storage operation in MountEmulatedStorage method.
  // Zygote process does not utilize root storage spaces and unshares its mount namespace below.

namespace android {
  // See storage config details at http://source.android.com/tech/storage/
  // Create private mount namespace shared by all children
  if (unshare(CLONE_NEWNS) == -1) {
    RuntimeAbort(env, __LINE__, "Failed to unshare()");
    return;
  }

static void com_android_internal_os_Zygote_nativeSecurityInit(JNIEnv*, jclass) {
  // security_getenforce is not allowed on app process. Initialize and cache
  // the value before zygote forks.
  g_is_security_enforced = security_getenforce();
  // Mark rootfs as being a slave so that changes from default
  // namespace only flow into our children.
  if (mount("rootfs", "/", nullptr, (MS_SLAVE | MS_REC), nullptr) == -1) {
    RuntimeAbort(env, __LINE__, "Failed to mount() rootfs as MS_SLAVE");
    return;
  }

  selinux_android_seapp_context_init();
  // Create a staging tmpfs that is shared by our children; they will
  // bind mount storage into their respective private namespaces, which
  // are isolated from each other.
  const char* target_base = getenv("EMULATED_STORAGE_TARGET");
  if (target_base != nullptr) {
#define STRINGIFY_UID(x) __STRING(x)
    if (mount("tmpfs", target_base, "tmpfs", MS_NOSUID | MS_NODEV,
              "uid=0,gid=" STRINGIFY_UID(AID_SDCARD_R) ",mode=0751") == -1) {
      ALOGE("Failed to mount tmpfs to %s", target_base);
      RuntimeAbort(env, __LINE__, "Failed to mount tmpfs");
      return;
    }
#undef STRINGIFY_UID
  }

  UnmountTree("/storage");
}

}  // anonymous namespace

namespace android {

static void com_android_internal_os_Zygote_nativePreApplicationInit(JNIEnv*, jclass) {
  PreApplicationInit();
}
@@ -1791,47 +1821,9 @@ static void com_android_internal_os_Zygote_nativeAllowFileAcrossFork(
    FileDescriptorWhitelist::Get()->Allow(path_cstr);
}

static void com_android_internal_os_Zygote_nativeUnmountStorageOnInit(JNIEnv* env, jclass) {
    // Zygote process unmount root storage space initially before every child processes are forked.
    // Every forked child processes (include SystemServer) only mount their own root storage space
    // and no need unmount storage operation in MountEmulatedStorage method.
    // Zygote process does not utilize root storage spaces and unshares its mount namespace below.

    // See storage config details at http://source.android.com/tech/storage/
    // Create private mount namespace shared by all children
    if (unshare(CLONE_NEWNS) == -1) {
        RuntimeAbort(env, __LINE__, "Failed to unshare()");
        return;
    }

    // Mark rootfs as being a slave so that changes from default
    // namespace only flow into our children.
    if (mount("rootfs", "/", nullptr, (MS_SLAVE | MS_REC), nullptr) == -1) {
        RuntimeAbort(env, __LINE__, "Failed to mount() rootfs as MS_SLAVE");
        return;
    }

    // Create a staging tmpfs that is shared by our children; they will
    // bind mount storage into their respective private namespaces, which
    // are isolated from each other.
    const char* target_base = getenv("EMULATED_STORAGE_TARGET");
    if (target_base != nullptr) {
#define STRINGIFY_UID(x) __STRING(x)
        if (mount("tmpfs", target_base, "tmpfs", MS_NOSUID | MS_NODEV,
                  "uid=0,gid=" STRINGIFY_UID(AID_SDCARD_R) ",mode=0751") == -1) {
            ALOGE("Failed to mount tmpfs to %s", target_base);
            RuntimeAbort(env, __LINE__, "Failed to mount tmpfs");
            return;
        }
#undef STRINGIFY_UID
    }

    UnmountTree("/storage");
}

static void com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter(
        JNIEnv* env, jclass, jint uidGidMin, jint uidGidMax) {
  if (!g_is_security_enforced) {
  if (!gIsSecurityEnforced) {
    ALOGI("seccomp disabled by setenforce 0");
    return;
  }
@@ -1883,8 +1875,12 @@ static void com_android_internal_os_Zygote_nativeSpecializeAppProcess(
 * @param is_primary  If this process is the primary or secondary Zygote; used to compute the name
 * of the environment variable storing the file descriptors.
 */
static void com_android_internal_os_Zygote_nativeGetSocketFDs(JNIEnv* env, jclass,
static void com_android_internal_os_Zygote_nativeInitNativeState(JNIEnv* env, jclass,
                                                                 jboolean is_primary) {
  /*
   * Obtain file descriptors created by init from the environment.
   */

  std::string android_socket_prefix(ANDROID_SOCKET_PREFIX);
  std::string env_var_name = android_socket_prefix + (is_primary ? "zygote" : "zygote_secondary");
  char* env_var_val = getenv(env_var_name.c_str());
@@ -1905,6 +1901,30 @@ static void com_android_internal_os_Zygote_nativeGetSocketFDs(JNIEnv* env, jclas
  } else {
    ALOGE("Unable to fetch USAP pool socket file descriptor");
  }

  /*
   * Security Initialization
   */

  // security_getenforce is not allowed on app process. Initialize and cache
  // the value before zygote forks.
  gIsSecurityEnforced = security_getenforce();

  selinux_android_seapp_context_init();

  /*
   * Storage Initialization
   */

  UnmountStorageOnInit(env);

  /*
   * Performance Initialization
   */

  if (!SetTaskProfiles(0, {})) {
    ZygoteFailure(env, "zygote", nullptr, "Zygote SetTaskProfiles failed");
  }
}

/**
@@ -2001,8 +2021,6 @@ static jboolean com_android_internal_os_Zygote_nativeDisableExecuteOnly(JNIEnv*
}

static const JNINativeMethod gMethods[] = {
    { "nativeSecurityInit", "()V",
      (void *) com_android_internal_os_Zygote_nativeSecurityInit },
    { "nativeForkAndSpecialize",
      "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)I",
      (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
@@ -2010,8 +2028,6 @@ static const JNINativeMethod gMethods[] = {
      (void *) com_android_internal_os_Zygote_nativeForkSystemServer },
    { "nativeAllowFileAcrossFork", "(Ljava/lang/String;)V",
      (void *) com_android_internal_os_Zygote_nativeAllowFileAcrossFork },
    { "nativeUnmountStorageOnInit", "()V",
      (void *) com_android_internal_os_Zygote_nativeUnmountStorageOnInit },
    { "nativePreApplicationInit", "()V",
      (void *) com_android_internal_os_Zygote_nativePreApplicationInit },
    { "nativeInstallSeccompUidGidFilter", "(II)V",
@@ -2021,8 +2037,8 @@ static const JNINativeMethod gMethods[] = {
    { "nativeSpecializeAppProcess",
      "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V",
      (void *) com_android_internal_os_Zygote_nativeSpecializeAppProcess },
    { "nativeGetSocketFDs", "(Z)V",
      (void *) com_android_internal_os_Zygote_nativeGetSocketFDs },
    { "nativeInitNativeState", "(Z)V",
      (void *) com_android_internal_os_Zygote_nativeInitNativeState },
    { "nativeGetUsapPipeFDs", "()[I",
      (void *) com_android_internal_os_Zygote_nativeGetUsapPipeFDs },
    { "nativeRemoveUsapTableEntry", "(I)Z",