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

Commit 9a81005e authored by David Sehr's avatar David Sehr
Browse files

Split fork and specialize in zygote

Separate the portions of the zygote jni library that perform forking
from specialization into system_server or app process.  This is a small
step towards separating forking into a pre-launch activity, possibly
with a pool of pre-application processes.

Bug: 68253328
Test: boot and run
Change-Id: I6ce694d9a69bf7d10cf61cd39989091ee9cabd37
Merged-In: I6ce694d9a69bf7d10cf61cd39989091ee9cabd37
parent b1fc5a4c
Loading
Loading
Loading
Loading
+219 −196
Original line number Diff line number Diff line
@@ -535,20 +535,14 @@ static bool FillFileDescriptorVector(JNIEnv* env,
  return true;
}

// Utility routine to fork zygote and specialize the child process.
static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
// Utility routine to specialize a zygote child process.
static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
                             jint runtime_flags, jobjectArray javaRlimits,
                             jlong permittedCapabilities, jlong effectiveCapabilities,
                                     jint mount_external,
                                     jstring java_se_info, jstring java_se_name,
                                     bool is_system_server, jintArray fdsToClose,
                                     jintArray fdsToIgnore, bool is_child_zygote,
                                     jstring instructionSet, jstring dataDir) {
  SetSignalHandlers();

  sigset_t sigchld;
  sigemptyset(&sigchld);
  sigaddset(&sigchld, SIGCHLD);
                             jint mount_external, jstring java_se_info, jstring java_se_name,
                             bool is_system_server, bool is_child_zygote, jstring instructionSet,
                             jstring dataDir) {
  std::string error_msg;

  auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg)
      __attribute__ ((noreturn)) {
@@ -568,57 +562,6 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
    __builtin_unreachable();
  };

  // Temporarily block SIGCHLD during forks. The SIGCHLD handler might
  // log, which would result in the logging FDs we close being reopened.
  // This would cause failures because the FDs are not whitelisted.
  //
  // Note that the zygote process is single threaded at this point.
  if (sigprocmask(SIG_BLOCK, &sigchld, nullptr) == -1) {
    fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
  }

  // Close any logging related FDs before we start evaluating the list of
  // file descriptors.
  __android_log_close();

  std::string error_msg;

  // If this is the first fork for this zygote, create the open FD table.
  // If it isn't, we just need to check whether the list of open files has
  // changed (and it shouldn't in the normal case).
  std::vector<int> fds_to_ignore;
  if (!FillFileDescriptorVector(env, fdsToIgnore, &fds_to_ignore, &error_msg)) {
    fail_fn(error_msg);
  }
  if (gOpenFdTable == NULL) {
    gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, &error_msg);
    if (gOpenFdTable == NULL) {
      fail_fn(error_msg);
    }
  } else if (!gOpenFdTable->Restat(fds_to_ignore, &error_msg)) {
    fail_fn(error_msg);
  }

  pid_t pid = fork();

  if (pid == 0) {
    PreApplicationInit();

    // Clean up any descriptors which must be closed immediately
    if (!DetachDescriptors(env, fdsToClose, &error_msg)) {
      fail_fn(error_msg);
    }

    // Re-open all remaining open file descriptors so that they aren't shared
    // with the zygote across a fork.
    if (!gOpenFdTable->ReopenOrDetach(&error_msg)) {
      fail_fn(error_msg);
    }

    if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
      fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
    }

  // Keep capabilities across UID change, unless we're staying root.
  if (uid != 0) {
    if (!EnableKeepCapabilities(&error_msg)) {
@@ -667,12 +610,11 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
          if (rc == -EROFS) {
              ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
          } else {
                ALOGE("createProcessGroup(%d, %d) failed: %s", uid, pid, strerror(-rc));
              ALOGE("createProcessGroup(%d, %d) failed: %s", uid, 0/*pid*/, strerror(-rc));
          }
      }
  }

    std::string error_msg;
  if (!SetGids(env, javaGids, &error_msg)) {
    fail_fn(error_msg);
  }
@@ -786,14 +728,90 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
  if (env->ExceptionCheck()) {
    fail_fn("Error calling post fork hooks.");
  }
  } else if (pid > 0) {
    // the parent process
}

// Utility routine to fork zygote and specialize the child process.
static pid_t ForkCommon(JNIEnv* env, jstring java_se_name, bool is_system_server,
                        jintArray fdsToClose, jintArray fdsToIgnore) {
  SetSignalHandlers();

  // Block SIGCHLD prior to fork.
  sigset_t sigchld;
  sigemptyset(&sigchld);
  sigaddset(&sigchld, SIGCHLD);

  auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg)
      __attribute__ ((noreturn)) {
    const char* se_name_c_str = nullptr;
    std::unique_ptr<ScopedUtfChars> se_name;
    if (java_se_name != nullptr) {
      se_name.reset(new ScopedUtfChars(env, java_se_name));
      se_name_c_str = se_name->c_str();
    }
    if (se_name_c_str == nullptr && is_system_server) {
      se_name_c_str = "system_server";
    }
    const std::string& error_msg = (se_name_c_str == nullptr)
        ? msg
        : StringPrintf("(%s) %s", se_name_c_str, msg.c_str());
    env->FatalError(error_msg.c_str());
    __builtin_unreachable();
  };

  // Temporarily block SIGCHLD during forks. The SIGCHLD handler might
  // log, which would result in the logging FDs we close being reopened.
  // This would cause failures because the FDs are not whitelisted.
  //
  // Note that the zygote process is single threaded at this point.
  if (sigprocmask(SIG_BLOCK, &sigchld, nullptr) == -1) {
    fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
  }

  // Close any logging related FDs before we start evaluating the list of
  // file descriptors.
  __android_log_close();

  std::string error_msg;

  // If this is the first fork for this zygote, create the open FD table.
  // If it isn't, we just need to check whether the list of open files has
  // changed (and it shouldn't in the normal case).
  std::vector<int> fds_to_ignore;
  if (!FillFileDescriptorVector(env, fdsToIgnore, &fds_to_ignore, &error_msg)) {
    fail_fn(error_msg);
  }
  if (gOpenFdTable == NULL) {
    gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, &error_msg);
    if (gOpenFdTable == NULL) {
      fail_fn(error_msg);
    }
  } else if (!gOpenFdTable->Restat(fds_to_ignore, &error_msg)) {
    fail_fn(error_msg);
  }

  pid_t pid = fork();

  if (pid == 0) {
    // The child process.
    PreApplicationInit();

    // Clean up any descriptors which must be closed immediately
    if (!DetachDescriptors(env, fdsToClose, &error_msg)) {
      fail_fn(error_msg);
    }

    // Re-open all remaining open file descriptors so that they aren't shared
    // with the zygote across a fork.
    if (!gOpenFdTable->ReopenOrDetach(&error_msg)) {
      fail_fn(error_msg);
    }
  }

  // We blocked SIGCHLD prior to a fork, we unblock it here.
  if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
    fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
  }
  }

  return pid;
}

@@ -879,22 +897,27 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
    // available.
    capabilities &= GetEffectiveCapabilityMask(env);

    return ForkAndSpecializeCommon(env, uid, gid, gids, runtime_flags,
            rlimits, capabilities, capabilities, mount_external, se_info,
            se_name, false, fdsToClose, fdsToIgnore, is_child_zygote == JNI_TRUE,
            instructionSet, appDataDir);
    pid_t pid = ForkCommon(env, se_name, false, fdsToClose, fdsToIgnore);
    if (pid == 0) {
      SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
                       capabilities, capabilities,
                       mount_external, se_info, se_name, false,
                       is_child_zygote == JNI_TRUE, instructionSet, appDataDir);
    }
    return pid;
}

static jint com_android_internal_os_Zygote_nativeForkSystemServer(
        JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
        jint runtime_flags, jobjectArray rlimits, jlong permittedCapabilities,
        jlong effectiveCapabilities) {
  pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
                                      runtime_flags, rlimits,
  pid_t pid = ForkCommon(env, NULL, true, NULL, NULL);
  if (pid == 0) {
      SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
                       permittedCapabilities, effectiveCapabilities,
                                      MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
                                      NULL, false, NULL, NULL);
  if (pid > 0) {
                       MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true,
                       false, NULL, NULL);
  } else 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;