Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  dalvik_system_ZygoteHooks.cc

  Sprache: C
 

/*
 * 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 "dalvik_system_ZygoteHooks.h"

#include <stdlib.h>

#include <android-base/logging.h>
#include <android-base/stringprintf.h>

#include "arch/instruction_set.h"
#include "art_method-inl.h"
#include "base/macros.h"
#include "base/mutex.h"
#include "base/runtime_debug.h"
#include "debugger.h"
#include "hidden_api.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
#include "jni/java_vm_ext.h"
#include "jni/jni_internal.h"
#include "native_util.h"
#include "nativehelper/jni_macros.h"
#include "nativehelper/scoped_utf_chars.h"
#include "non_debuggable_classes.h"
#include "oat/oat_file.h"
#include "oat/oat_file_manager.h"
#include "scoped_thread_state_change-inl.h"
#include "stack.h"
#include "startup_completed_task.h"
#include "thread-current-inl.h"
#include "thread_list.h"
#include "trace.h"

#include <sys/resource.h>

namespace art HIDDEN {

// Set to true to always determine the non-debuggable classes even if we would not allow a debugger
// to actually attach.
static bool kAlwaysCollectNonDebuggableClasses =
    RegisterRuntimeDebugFlag(&kAlwaysCollectNonDebuggableClasses);

using android::base::StringPrintf;

class ClassSet {
 public:
  // The number of classes we reasonably expect to have to look at. Realistically the number is more
  // ~10 but there is little harm in having some extra.
  static constexpr int kClassSetCapacity = 100;

  explicit ClassSet(Thread* const self) : self_(self) {
    self_->GetJniEnv()->PushFrame(kClassSetCapacity);
  }

  ~ClassSet() {
    self_->GetJniEnv()->PopFrame();
  }

  void AddClass(ObjPtr<mirror::Class> klass) REQUIRES(Locks::mutator_lock_) {
    class_set_.insert(self_->GetJniEnv()->AddLocalReference<jclass>(klass));
  }

  const std::unordered_set<jclass>& GetClasses() const {
    return class_set_;
  }

 private:
  Thread* const self_;
  std::unordered_set<jclass> class_set_;
};

static void DoCollectNonDebuggableCallback(Thread* thread, void* data)
    REQUIRES(Locks::mutator_lock_) {
  class NonDebuggableStacksVisitor : public StackVisitor {
   public:
    NonDebuggableStacksVisitor(Thread* t, ClassSet* class_set)
        : StackVisitor(t, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
          class_set_(class_set) {}

    ~NonDebuggableStacksVisitor() override {}

    bool VisitFrame() override REQUIRES(Locks::mutator_lock_) {
      if (GetMethod()->IsRuntimeMethod()) {
        return true;
      }
      class_set_->AddClass(GetMethod()->GetDeclaringClass());
      if (kIsDebugBuild) {
        LOG(INFO) << GetMethod()->GetDeclaringClass()->PrettyClass()
                  << " might not be fully debuggable/deoptimizable due to "
                  << GetMethod()->PrettyMethod() << " appearing on the stack during zygote fork.";
      }
      return true;
    }

   private:
    ClassSet* class_set_;
  };
  NonDebuggableStacksVisitor visitor(thread, reinterpret_cast<ClassSet*>(data));
  visitor.WalkStack();
}

static void CollectNonDebuggableClasses() REQUIRES(!Locks::mutator_lock_) {
  Runtime* const runtime = Runtime::Current();
  Thread* const self = Thread::Current();
  // Get the mutator lock.
  ScopedObjectAccess soa(self);
  ClassSet classes(self);
  {
    // Drop the shared mutator lock.
    ScopedThreadSuspension sts(self, art::ThreadState::kNative);
    // Get exclusive mutator lock with suspend all.
    ScopedSuspendAll suspend("Checking stacks for non-obsoletable methods!",
                             /*long_suspend=*/false);
    MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
    runtime->GetThreadList()->ForEach(DoCollectNonDebuggableCallback, &classes);
  }
  for (jclass klass : classes.GetClasses()) {
    NonDebuggableClasses::AddNonDebuggableClass(klass);
  }
}

// Must match values in com.android.internal.os.Zygote.
enum {
  DEBUG_ENABLE_JDWP                   = 1,
  DEBUG_ENABLE_CHECKJNI               = 1 << 1,
  DEBUG_ENABLE_ASSERT                 = 1 << 2,
  DEBUG_ENABLE_SAFEMODE               = 1 << 3,
  DEBUG_ENABLE_JNI_LOGGING            = 1 << 4,
  DEBUG_GENERATE_DEBUG_INFO           = 1 << 5,
  DEBUG_ALWAYS_JIT                    = 1 << 6,
  DEBUG_NATIVE_DEBUGGABLE             = 1 << 7,
  DEBUG_JAVA_DEBUGGABLE               = 1 << 8,
  DISABLE_VERIFIER                    = 1 << 9,
  ONLY_USE_TRUSTED_OAT_FILES          = 1 << 10,  // Formerly ONLY_USE_SYSTEM_OAT_FILES
  DEBUG_GENERATE_MINI_DEBUG_INFO      = 1 << 11,
  HIDDEN_API_ENFORCEMENT_POLICY_MASK  = (1 << 12)
                                      | (1 << 13),
  PROFILE_SYSTEM_SERVER               = 1 << 14,
  PROFILE_FROM_SHELL                  = 1 << 15,
  USE_APP_IMAGE_STARTUP_CACHE         = 1 << 16,
  DEBUG_IGNORE_APP_SIGNAL_HANDLER     = 1 << 17,
  DISABLE_TEST_API_ENFORCEMENT_POLICY = 1 << 18,
  PROFILEABLE                         = 1 << 24,

  // bits to shift (flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) by to get a value
  // corresponding to hiddenapi::EnforcementPolicy
  API_ENFORCEMENT_POLICY_SHIFT = CTZ(HIDDEN_API_ENFORCEMENT_POLICY_MASK),
};

static uint32_t EnableDebugFeatures(uint32_t runtime_flags) {
  Runtime* const runtime = Runtime::Current();
  if ((runtime_flags & DEBUG_ENABLE_CHECKJNI) != 0) {
    JavaVMExt* vm = runtime->GetJavaVM();
    if (!vm->IsCheckJniEnabled()) {
      LOG(INFO) << "Late-enabling -Xcheck:jni";
      vm->SetCheckJniEnabled(true);
      // This is the only thread that's running at this point and the above call sets
      // the CheckJNI flag in the corresponding `JniEnvExt`.
      DCHECK(Thread::Current()->GetJniEnv()->IsCheckJniEnabled());
    } else {
      LOG(INFO) << "Not late-enabling -Xcheck:jni (already on)";
    }
    runtime_flags &= ~DEBUG_ENABLE_CHECKJNI;
  }

  if ((runtime_flags & DEBUG_ENABLE_JNI_LOGGING) != 0) {
    gLogVerbosity.third_party_jni = true;
    runtime_flags &= ~DEBUG_ENABLE_JNI_LOGGING;
  }

  Dbg::SetJdwpAllowed((runtime_flags & DEBUG_ENABLE_JDWP) != 0);
  runtime_flags &= ~DEBUG_ENABLE_JDWP;

  const bool safe_mode = (runtime_flags & DEBUG_ENABLE_SAFEMODE) != 0;
  if (safe_mode) {
    // Only verify oat files.
    runtime->AddCompilerOption("--compiler-filter=verify");
    runtime->SetSafeMode(true);
    runtime_flags &= ~DEBUG_ENABLE_SAFEMODE;
  }

  // This is for backwards compatibility with Dalvik.
  runtime_flags &= ~DEBUG_ENABLE_ASSERT;

  if ((runtime_flags & DEBUG_ALWAYS_JIT) != 0) {
    jit::JitOptions* jit_options = runtime->GetJITOptions();
    CHECK(jit_options != nullptr);
    jit_options->SetJitAtFirstUse();
    runtime_flags &= ~DEBUG_ALWAYS_JIT;
  }

  bool needs_non_debuggable_classes = false;
  if ((runtime_flags & DEBUG_JAVA_DEBUGGABLE) != 0) {
    runtime->AddCompilerOption("--debuggable");
    runtime_flags |= DEBUG_GENERATE_MINI_DEBUG_INFO;
    runtime->SetRuntimeDebugState(Runtime::RuntimeDebugState::kJavaDebuggableAtInit);
    {
      // Deoptimize the boot image as it may be non-debuggable.
      ScopedSuspendAll ssa(__FUNCTION__);
      runtime->DeoptimizeBootImage();
    }
    runtime_flags &= ~DEBUG_JAVA_DEBUGGABLE;
    needs_non_debuggable_classes = true;
  }
  if (needs_non_debuggable_classes || kAlwaysCollectNonDebuggableClasses) {
    CollectNonDebuggableClasses();
  }

  if ((runtime_flags & DEBUG_NATIVE_DEBUGGABLE) != 0) {
    runtime->AddCompilerOption("--debuggable");
    runtime_flags |= DEBUG_GENERATE_DEBUG_INFO;
    runtime->SetNativeDebuggable(true);
    runtime_flags &= ~DEBUG_NATIVE_DEBUGGABLE;
  }

  if ((runtime_flags & DEBUG_GENERATE_MINI_DEBUG_INFO) != 0) {
    // Generate native minimal debug information to allow backtracing.
    runtime->AddCompilerOption("--generate-mini-debug-info");
    runtime_flags &= ~DEBUG_GENERATE_MINI_DEBUG_INFO;
  }

  if ((runtime_flags & DEBUG_GENERATE_DEBUG_INFO) != 0) {
    // Generate all native debug information we can (e.g. line-numbers).
    runtime->AddCompilerOption("--generate-debug-info");
    runtime_flags &= ~DEBUG_GENERATE_DEBUG_INFO;
  }

  if ((runtime_flags & DEBUG_IGNORE_APP_SIGNAL_HANDLER) != 0) {
    runtime->SetSignalHookDebuggable(true);
    runtime_flags &= ~DEBUG_IGNORE_APP_SIGNAL_HANDLER;
  }

  runtime->SetProfileableFromShell((runtime_flags & PROFILE_FROM_SHELL) != 0);
  runtime_flags &= ~PROFILE_FROM_SHELL;
  runtime->SetProfileable((runtime_flags & PROFILEABLE) != 0);
  runtime_flags &= ~PROFILEABLE;

  return runtime_flags;
}

static jlong ZygoteHooks_nativePreFork(JNIEnv* env, jclass) {
  Runtime* runtime = Runtime::Current();
  CHECK(runtime->IsZygote()) << "runtime instance not started with -Xzygote";

  runtime->PreZygoteFork();

  // Grab thread before fork potentially makes Thread::pthread_key_self_ unusable.
  return reinterpret_cast<jlong>(Thread::ForEnv(env));
}

static void ZygoteHooks_nativePostZygoteFork(JNIEnv*, jclass) {
  Runtime::Current()->PostZygoteFork();
}

static void ZygoteHooks_nativePostForkSystemServer([[maybe_unused]] JNIEnv* env,
                                                   [[maybe_unused]] jclass klass,
                                                   jint runtime_flags) {
  // Reload the current flags first. In case we need to take actions based on them.
  Runtime::Current()->ReloadAllFlags(__FUNCTION__);

  // Set the runtime state as the first thing, in case JIT and other services
  // start querying it.
  Runtime::Current()->SetAsSystemServer();

  // This JIT code cache for system server is created whilst the runtime is still single threaded.
  // System server has a window where it can create executable pages for this purpose, but this is
  // turned off after this hook. Consequently, the only JIT mode supported is the dual-view JIT
  // where one mapping is R->RW and the other is RX. Single view requires RX->RWX->RX.
  if (Runtime::Current()->GetJit() != nullptr) {
    Runtime::Current()->GetJit()->GetCodeCache()->PostForkChildAction(
        /* is_system_server= */ true, /* is_zygote= */ false);
  }
  // Enable profiling if required based on the flags. This is done here instead of in
  // nativePostForkChild since nativePostForkChild is called after loading the system server oat
  // files.
  bool profile_system_server = (runtime_flags & PROFILE_SYSTEM_SERVER) == PROFILE_SYSTEM_SERVER;
  Runtime::Current()->GetJITOptions()->SetSaveProfilingInfo(profile_system_server);
}

static void ZygoteHooks_nativePostForkChild(JNIEnv* env,
                                            jclass,
                                            jlong token,
                                            jint runtime_flags,
                                            jboolean is_system_server,
                                            jboolean is_zygote,
                                            jstring instruction_set) {
  DCHECK(!(is_system_server && is_zygote));
  // Reload the current flags first. In case we need to take any updated actions.
  Runtime::Current()->ReloadAllFlags(__FUNCTION__);
  // Then, set the runtime state, in case JIT and other services
  // start querying it.
  Runtime::Current()->SetAsZygoteChild(is_system_server, is_zygote);

  Thread* thread = reinterpret_cast<Thread*>(token);
  // Our system thread ID, etc, has changed so reset Thread state.
  thread->InitAfterFork();
  runtime_flags = EnableDebugFeatures(runtime_flags);
  hiddenapi::EnforcementPolicy api_enforcement_policy = hiddenapi::EnforcementPolicy::kDisabled;

  Runtime* runtime = Runtime::Current();

  if ((runtime_flags & DISABLE_VERIFIER) != 0) {
    runtime->DisableVerifier();
    runtime_flags &= ~DISABLE_VERIFIER;
  }

  if ((runtime_flags & ONLY_USE_TRUSTED_OAT_FILES) == 0 && !is_system_server) {
    runtime->GetOatFileManager().ClearOnlyUseTrustedOatFiles();
  }
  runtime_flags &= ~ONLY_USE_TRUSTED_OAT_FILES;

  api_enforcement_policy = hiddenapi::EnforcementPolicyFromInt(
      (runtime_flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) >> API_ENFORCEMENT_POLICY_SHIFT);
  runtime_flags &= ~HIDDEN_API_ENFORCEMENT_POLICY_MASK;

  if ((runtime_flags & DISABLE_TEST_API_ENFORCEMENT_POLICY) != 0u) {
    runtime->SetTestApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kDisabled);
  } else {
    runtime->SetTestApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled);
  }
  runtime_flags &= ~DISABLE_TEST_API_ENFORCEMENT_POLICY;

  bool profile_system_server = (runtime_flags & PROFILE_SYSTEM_SERVER) == PROFILE_SYSTEM_SERVER;
  runtime_flags &= ~PROFILE_SYSTEM_SERVER;

  runtime->SetLoadAppImageStartupCacheEnabled(
      (runtime_flags & USE_APP_IMAGE_STARTUP_CACHE) != 0u);
  runtime_flags &= ~USE_APP_IMAGE_STARTUP_CACHE;

  if (runtime_flags != 0) {
    LOG(ERROR) << StringPrintf("Unknown bits set in runtime_flags: %#x", runtime_flags);
  }

  runtime->GetHeap()->PostForkChildAction(thread);

  if (!is_zygote) {
    // Setup an app startup complete task in case the app doesn't notify it
    // through VMRuntime::notifyStartupCompleted.
    static constexpr uint64_t kMaxAppStartupTimeNs = MsToNs(5000);  // 5 seconds
    runtime->GetHeap()->AddHeapTask(new StartupCompletedTask(NanoTime() + kMaxAppStartupTimeNs));
  }

  if (runtime->GetJit() != nullptr) {
    if (!is_system_server) {
      // System server already called the JIT cache post fork action in `nativePostForkSystemServer`.
      runtime->GetJit()->GetCodeCache()->PostForkChildAction(
          /* is_system_server= */ false, is_zygote);
    }
    // This must be called after EnableDebugFeatures.
    runtime->GetJit()->PostForkChildAction(is_system_server, is_zygote);
  }

  // Update tracing.
  if (Trace::GetMethodTracingMode() != TracingMode::kTracingInactive) {
    TraceOutputMode output_mode = Trace::GetOutputMode();
    Trace::TraceMode trace_mode = Trace::GetMode();
    size_t buffer_size = Trace::GetBufferSize();
    int flags = Trace::GetFlags();
    int interval = Trace::GetIntervalInMillis();

    // Just drop it.
    Trace::Abort();

    // Only restart if it was streaming mode.
    // TODO: Expose buffer size, so we can also do file mode.
    if (output_mode == TraceOutputMode::kStreaming) {
      static constexpr size_t kMaxProcessNameLength = 100;
      char name_buf[kMaxProcessNameLength] = {};
      int rc = pthread_getname_np(pthread_self(), name_buf, kMaxProcessNameLength);
      std::string proc_name;

      if (rc == 0) {
          // On success use the pthread name.
          proc_name = name_buf;
      }

      if (proc_name.empty() || proc_name == "zygote" || proc_name == "zygote64") {
        // Either no process name, or the name hasn't been changed, yet. Just use pid.
        pid_t pid = getpid();
        proc_name = StringPrintf("%u"static_cast<uint32_t>(pid));
      }

      const char* path = kIsTargetBuild ? "/data/misc/trace" : "/tmp";
      std::string trace_file = StringPrintf("%s/%s.trace.bin", path, proc_name.c_str());
      Trace::Start(trace_file.c_str(),
                   buffer_size,
                   flags,
                   output_mode,
                   trace_mode,
                   interval);
      if (thread->IsExceptionPending()) {
        ScopedObjectAccess soa(env);
        thread->ClearException();
      }
    }
  }

  bool do_hidden_api_checks = api_enforcement_policy != hiddenapi::EnforcementPolicy::kDisabled;
  DCHECK(!(is_system_server && do_hidden_api_checks))
      << "SystemServer should be forked with EnforcementPolicy::kDisable";
  DCHECK(!(is_zygote && do_hidden_api_checks))
      << "Child zygote processes should be forked with EnforcementPolicy::kDisable";
  runtime->SetHiddenApiEnforcementPolicy(api_enforcement_policy);
  runtime->SetDedupeHiddenApiWarnings(true);
  if (api_enforcement_policy != hiddenapi::EnforcementPolicy::kDisabled &&
      runtime->GetHiddenApiEventLogSampleRate() != 0) {
    // Hidden API checks are enabled, and we are sampling access for the event log. Initialize the
    // random seed, to ensure the sampling is actually random. We do this post-fork, as doing it
    // pre-fork would result in the same sequence for every forked process.
    std::srand(static_cast<uint32_t>(NanoTime()));
  }

  if (instruction_set != nullptr && !is_system_server) {
    ScopedUtfChars isa_string(env, instruction_set);
    InstructionSet isa = GetInstructionSetFromString(isa_string.c_str());
    Runtime::NativeBridgeAction action = Runtime::NativeBridgeAction::kUnload;
    if (isa != InstructionSet::kNone && isa != kRuntimeISA) {
      action = Runtime::NativeBridgeAction::kInitialize;
    }
    runtime->InitNonZygoteOrPostFork(env, is_system_server, is_zygote, action, isa_string.c_str());
  } else {
    runtime->InitNonZygoteOrPostFork(
        env,
        is_system_server,
        is_zygote,
        Runtime::NativeBridgeAction::kUnload,
        /*isa=*/ nullptr,
        profile_system_server);
  }
}

static void ZygoteHooks_startZygoteNoThreadCreation([[maybe_unused]] JNIEnv* env,
                                                    [[maybe_unused]] jclass klass) {
  Runtime::Current()->SetZygoteNoThreadSection(true);
}

static void ZygoteHooks_stopZygoteNoThreadCreation([[maybe_unused]] JNIEnv* env,
                                                   [[maybe_unused]] jclass klass) {
  Runtime::Current()->SetZygoteNoThreadSection(false);
}

static jboolean ZygoteHooks_nativeZygoteLongSuspendOk([[maybe_unused]] JNIEnv* env,
                                                      [[maybe_unused]] jclass klass) {
  // Indefinite thread suspensions are not OK if we're supposed to be JIT-compiling for other
  // processes.  We only care about JIT compilation that affects other processes.  The zygote
  // itself doesn't run appreciable amounts of Java code when running single-threaded, so
  // suspending the JIT in non-jit-zygote mode is OK.
  // TODO: Make this potentially return true once we're done with JIT compilation in JIT Zygote.
  // Only called in zygote. Thus static is OK here.
  static bool isJitZygote = jit::Jit::InZygoteUsingJit();
  static bool explicitlyDisabled = Runtime::Current()->IsJavaZygoteForkLoopRequired();
  return (isJitZygote || explicitlyDisabled) ? JNI_FALSE : JNI_TRUE;
}

static JNINativeMethod gMethods[] = {
  NATIVE_METHOD(ZygoteHooks, nativePreFork, "()J"),
  NATIVE_METHOD(ZygoteHooks, nativePostZygoteFork, "()V"),
  NATIVE_METHOD(ZygoteHooks, nativePostForkSystemServer, "(I)V"),
  NATIVE_METHOD(ZygoteHooks, nativePostForkChild, "(JIZZLjava/lang/String;)V"),
  NATIVE_METHOD(ZygoteHooks, nativeZygoteLongSuspendOk, "()Z"),
  NATIVE_METHOD(ZygoteHooks, startZygoteNoThreadCreation, "()V"),
  NATIVE_METHOD(ZygoteHooks, stopZygoteNoThreadCreation, "()V"),
};

void register_dalvik_system_ZygoteHooks(JNIEnv* env) {
  REGISTER_NATIVE_METHODS("dalvik/system/ZygoteHooks");
}

}  // namespace art

Messung V0.5 in Prozent
C=89 H=92 G=90

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet am  2026-06-29) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik