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

Commit f40f0522 authored by David Sehr's avatar David Sehr Committed by Gerrit Code Review
Browse files

Merge "Split fork and specialize in zygote"

parents c00dd281 9a81005e
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;