• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "dalvik_system_ZygoteHooks.h"
18 
19 #include <stdlib.h>
20 
21 #include <android-base/logging.h>
22 #include <android-base/stringprintf.h>
23 
24 #include "arch/instruction_set.h"
25 #include "art_method-inl.h"
26 #include "base/macros.h"
27 #include "base/mutex.h"
28 #include "base/runtime_debug.h"
29 #include "debugger.h"
30 #include "hidden_api.h"
31 #include "jit/jit.h"
32 #include "jit/jit_code_cache.h"
33 #include "jni/java_vm_ext.h"
34 #include "jni/jni_internal.h"
35 #include "native_util.h"
36 #include "nativehelper/jni_macros.h"
37 #include "nativehelper/scoped_utf_chars.h"
38 #include "non_debuggable_classes.h"
39 #include "oat_file.h"
40 #include "oat_file_manager.h"
41 #include "scoped_thread_state_change-inl.h"
42 #include "stack.h"
43 #include "startup_completed_task.h"
44 #include "thread-current-inl.h"
45 #include "thread_list.h"
46 #include "trace.h"
47 
48 #include <sys/resource.h>
49 
50 namespace art {
51 
52 // Set to true to always determine the non-debuggable classes even if we would not allow a debugger
53 // to actually attach.
54 static bool kAlwaysCollectNonDebuggableClasses =
55     RegisterRuntimeDebugFlag(&kAlwaysCollectNonDebuggableClasses);
56 
57 using android::base::StringPrintf;
58 
59 class ClassSet {
60  public:
61   // The number of classes we reasonably expect to have to look at. Realistically the number is more
62   // ~10 but there is little harm in having some extra.
63   static constexpr int kClassSetCapacity = 100;
64 
ClassSet(Thread * const self)65   explicit ClassSet(Thread* const self) : self_(self) {
66     self_->GetJniEnv()->PushFrame(kClassSetCapacity);
67   }
68 
~ClassSet()69   ~ClassSet() {
70     self_->GetJniEnv()->PopFrame();
71   }
72 
AddClass(ObjPtr<mirror::Class> klass)73   void AddClass(ObjPtr<mirror::Class> klass) REQUIRES(Locks::mutator_lock_) {
74     class_set_.insert(self_->GetJniEnv()->AddLocalReference<jclass>(klass));
75   }
76 
GetClasses() const77   const std::unordered_set<jclass>& GetClasses() const {
78     return class_set_;
79   }
80 
81  private:
82   Thread* const self_;
83   std::unordered_set<jclass> class_set_;
84 };
85 
DoCollectNonDebuggableCallback(Thread * thread,void * data)86 static void DoCollectNonDebuggableCallback(Thread* thread, void* data)
87     REQUIRES(Locks::mutator_lock_) {
88   class NonDebuggableStacksVisitor : public StackVisitor {
89    public:
90     NonDebuggableStacksVisitor(Thread* t, ClassSet* class_set)
91         : StackVisitor(t, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
92           class_set_(class_set) {}
93 
94     ~NonDebuggableStacksVisitor() override {}
95 
96     bool VisitFrame() override REQUIRES(Locks::mutator_lock_) {
97       if (GetMethod()->IsRuntimeMethod()) {
98         return true;
99       }
100       class_set_->AddClass(GetMethod()->GetDeclaringClass());
101       if (kIsDebugBuild) {
102         LOG(INFO) << GetMethod()->GetDeclaringClass()->PrettyClass()
103                   << " might not be fully debuggable/deoptimizable due to "
104                   << GetMethod()->PrettyMethod() << " appearing on the stack during zygote fork.";
105       }
106       return true;
107     }
108 
109    private:
110     ClassSet* class_set_;
111   };
112   NonDebuggableStacksVisitor visitor(thread, reinterpret_cast<ClassSet*>(data));
113   visitor.WalkStack();
114 }
115 
CollectNonDebuggableClasses()116 static void CollectNonDebuggableClasses() REQUIRES(!Locks::mutator_lock_) {
117   Runtime* const runtime = Runtime::Current();
118   Thread* const self = Thread::Current();
119   // Get the mutator lock.
120   ScopedObjectAccess soa(self);
121   ClassSet classes(self);
122   {
123     // Drop the shared mutator lock.
124     ScopedThreadSuspension sts(self, art::ThreadState::kNative);
125     // Get exclusive mutator lock with suspend all.
126     ScopedSuspendAll suspend("Checking stacks for non-obsoletable methods!",
127                              /*long_suspend=*/false);
128     MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
129     runtime->GetThreadList()->ForEach(DoCollectNonDebuggableCallback, &classes);
130   }
131   for (jclass klass : classes.GetClasses()) {
132     NonDebuggableClasses::AddNonDebuggableClass(klass);
133   }
134 }
135 
136 // Must match values in com.android.internal.os.Zygote.
137 enum {
138   DEBUG_ENABLE_JDWP                   = 1,
139   DEBUG_ENABLE_CHECKJNI               = 1 << 1,
140   DEBUG_ENABLE_ASSERT                 = 1 << 2,
141   DEBUG_ENABLE_SAFEMODE               = 1 << 3,
142   DEBUG_ENABLE_JNI_LOGGING            = 1 << 4,
143   DEBUG_GENERATE_DEBUG_INFO           = 1 << 5,
144   DEBUG_ALWAYS_JIT                    = 1 << 6,
145   DEBUG_NATIVE_DEBUGGABLE             = 1 << 7,
146   DEBUG_JAVA_DEBUGGABLE               = 1 << 8,
147   DISABLE_VERIFIER                    = 1 << 9,
148   ONLY_USE_TRUSTED_OAT_FILES          = 1 << 10,  // Formerly ONLY_USE_SYSTEM_OAT_FILES
149   DEBUG_GENERATE_MINI_DEBUG_INFO      = 1 << 11,
150   HIDDEN_API_ENFORCEMENT_POLICY_MASK  = (1 << 12)
151                                       | (1 << 13),
152   PROFILE_SYSTEM_SERVER               = 1 << 14,
153   PROFILE_FROM_SHELL                  = 1 << 15,
154   USE_APP_IMAGE_STARTUP_CACHE         = 1 << 16,
155   DEBUG_IGNORE_APP_SIGNAL_HANDLER     = 1 << 17,
156   DISABLE_TEST_API_ENFORCEMENT_POLICY = 1 << 18,
157   PROFILEABLE                         = 1 << 24,
158 
159   // bits to shift (flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) by to get a value
160   // corresponding to hiddenapi::EnforcementPolicy
161   API_ENFORCEMENT_POLICY_SHIFT = CTZ(HIDDEN_API_ENFORCEMENT_POLICY_MASK),
162 };
163 
EnableDebugFeatures(uint32_t runtime_flags)164 static uint32_t EnableDebugFeatures(uint32_t runtime_flags) {
165   Runtime* const runtime = Runtime::Current();
166   if ((runtime_flags & DEBUG_ENABLE_CHECKJNI) != 0) {
167     JavaVMExt* vm = runtime->GetJavaVM();
168     if (!vm->IsCheckJniEnabled()) {
169       LOG(INFO) << "Late-enabling -Xcheck:jni";
170       vm->SetCheckJniEnabled(true);
171       // This is the only thread that's running at this point and the above call sets
172       // the CheckJNI flag in the corresponding `JniEnvExt`.
173       DCHECK(Thread::Current()->GetJniEnv()->IsCheckJniEnabled());
174     } else {
175       LOG(INFO) << "Not late-enabling -Xcheck:jni (already on)";
176     }
177     runtime_flags &= ~DEBUG_ENABLE_CHECKJNI;
178   }
179 
180   if ((runtime_flags & DEBUG_ENABLE_JNI_LOGGING) != 0) {
181     gLogVerbosity.third_party_jni = true;
182     runtime_flags &= ~DEBUG_ENABLE_JNI_LOGGING;
183   }
184 
185   Dbg::SetJdwpAllowed((runtime_flags & DEBUG_ENABLE_JDWP) != 0);
186   runtime_flags &= ~DEBUG_ENABLE_JDWP;
187 
188   const bool safe_mode = (runtime_flags & DEBUG_ENABLE_SAFEMODE) != 0;
189   if (safe_mode) {
190     // Only quicken oat files.
191     runtime->AddCompilerOption("--compiler-filter=quicken");
192     runtime->SetSafeMode(true);
193     runtime_flags &= ~DEBUG_ENABLE_SAFEMODE;
194   }
195 
196   // This is for backwards compatibility with Dalvik.
197   runtime_flags &= ~DEBUG_ENABLE_ASSERT;
198 
199   if ((runtime_flags & DEBUG_ALWAYS_JIT) != 0) {
200     jit::JitOptions* jit_options = runtime->GetJITOptions();
201     CHECK(jit_options != nullptr);
202     jit_options->SetJitAtFirstUse();
203     runtime_flags &= ~DEBUG_ALWAYS_JIT;
204   }
205 
206   bool needs_non_debuggable_classes = false;
207   if ((runtime_flags & DEBUG_JAVA_DEBUGGABLE) != 0) {
208     runtime->AddCompilerOption("--debuggable");
209     runtime_flags |= DEBUG_GENERATE_MINI_DEBUG_INFO;
210     runtime->SetRuntimeDebugState(Runtime::RuntimeDebugState::kJavaDebuggableAtInit);
211     {
212       // Deoptimize the boot image as it may be non-debuggable.
213       ScopedSuspendAll ssa(__FUNCTION__);
214       runtime->DeoptimizeBootImage();
215     }
216     runtime_flags &= ~DEBUG_JAVA_DEBUGGABLE;
217     needs_non_debuggable_classes = true;
218   }
219   if (needs_non_debuggable_classes || kAlwaysCollectNonDebuggableClasses) {
220     CollectNonDebuggableClasses();
221   }
222 
223   if ((runtime_flags & DEBUG_NATIVE_DEBUGGABLE) != 0) {
224     runtime->AddCompilerOption("--debuggable");
225     runtime_flags |= DEBUG_GENERATE_DEBUG_INFO;
226     runtime->SetNativeDebuggable(true);
227     runtime_flags &= ~DEBUG_NATIVE_DEBUGGABLE;
228   }
229 
230   if ((runtime_flags & DEBUG_GENERATE_MINI_DEBUG_INFO) != 0) {
231     // Generate native minimal debug information to allow backtracing.
232     runtime->AddCompilerOption("--generate-mini-debug-info");
233     runtime_flags &= ~DEBUG_GENERATE_MINI_DEBUG_INFO;
234   }
235 
236   if ((runtime_flags & DEBUG_GENERATE_DEBUG_INFO) != 0) {
237     // Generate all native debug information we can (e.g. line-numbers).
238     runtime->AddCompilerOption("--generate-debug-info");
239     runtime_flags &= ~DEBUG_GENERATE_DEBUG_INFO;
240   }
241 
242   if ((runtime_flags & DEBUG_IGNORE_APP_SIGNAL_HANDLER) != 0) {
243     runtime->SetSignalHookDebuggable(true);
244     runtime_flags &= ~DEBUG_IGNORE_APP_SIGNAL_HANDLER;
245   }
246 
247   runtime->SetProfileableFromShell((runtime_flags & PROFILE_FROM_SHELL) != 0);
248   runtime_flags &= ~PROFILE_FROM_SHELL;
249   runtime->SetProfileable((runtime_flags & PROFILEABLE) != 0);
250   runtime_flags &= ~PROFILEABLE;
251 
252   return runtime_flags;
253 }
254 
ZygoteHooks_nativePreFork(JNIEnv * env,jclass)255 static jlong ZygoteHooks_nativePreFork(JNIEnv* env, jclass) {
256   Runtime* runtime = Runtime::Current();
257   CHECK(runtime->IsZygote()) << "runtime instance not started with -Xzygote";
258 
259   runtime->PreZygoteFork();
260 
261   // Grab thread before fork potentially makes Thread::pthread_key_self_ unusable.
262   return reinterpret_cast<jlong>(Thread::ForEnv(env));
263 }
264 
ZygoteHooks_nativePostZygoteFork(JNIEnv *,jclass)265 static void ZygoteHooks_nativePostZygoteFork(JNIEnv*, jclass) {
266   Runtime::Current()->PostZygoteFork();
267 }
268 
ZygoteHooks_nativePostForkSystemServer(JNIEnv * env ATTRIBUTE_UNUSED,jclass klass ATTRIBUTE_UNUSED,jint runtime_flags)269 static void ZygoteHooks_nativePostForkSystemServer(JNIEnv* env ATTRIBUTE_UNUSED,
270                                                    jclass klass ATTRIBUTE_UNUSED,
271                                                    jint runtime_flags) {
272   // Reload the current flags first. In case we need to take actions based on them.
273   Runtime::Current()->ReloadAllFlags(__FUNCTION__);
274 
275   // Set the runtime state as the first thing, in case JIT and other services
276   // start querying it.
277   Runtime::Current()->SetAsSystemServer();
278 
279   // This JIT code cache for system server is created whilst the runtime is still single threaded.
280   // System server has a window where it can create executable pages for this purpose, but this is
281   // turned off after this hook. Consequently, the only JIT mode supported is the dual-view JIT
282   // where one mapping is R->RW and the other is RX. Single view requires RX->RWX->RX.
283   if (Runtime::Current()->GetJit() != nullptr) {
284     Runtime::Current()->GetJit()->GetCodeCache()->PostForkChildAction(
285         /* is_system_server= */ true, /* is_zygote= */ false);
286   }
287   // Enable profiling if required based on the flags. This is done here instead of in
288   // nativePostForkChild since nativePostForkChild is called after loading the system server oat
289   // files.
290   bool profile_system_server = (runtime_flags & PROFILE_SYSTEM_SERVER) == PROFILE_SYSTEM_SERVER;
291   Runtime::Current()->GetJITOptions()->SetSaveProfilingInfo(profile_system_server);
292 }
293 
ZygoteHooks_nativePostForkChild(JNIEnv * env,jclass,jlong token,jint runtime_flags,jboolean is_system_server,jboolean is_zygote,jstring instruction_set)294 static void ZygoteHooks_nativePostForkChild(JNIEnv* env,
295                                             jclass,
296                                             jlong token,
297                                             jint runtime_flags,
298                                             jboolean is_system_server,
299                                             jboolean is_zygote,
300                                             jstring instruction_set) {
301   DCHECK(!(is_system_server && is_zygote));
302   // Reload the current flags first. In case we need to take any updated actions.
303   Runtime::Current()->ReloadAllFlags(__FUNCTION__);
304   // Then, set the runtime state, in case JIT and other services
305   // start querying it.
306   Runtime::Current()->SetAsZygoteChild(is_system_server, is_zygote);
307 
308   Thread* thread = reinterpret_cast<Thread*>(token);
309   // Our system thread ID, etc, has changed so reset Thread state.
310   thread->InitAfterFork();
311   runtime_flags = EnableDebugFeatures(runtime_flags);
312   hiddenapi::EnforcementPolicy api_enforcement_policy = hiddenapi::EnforcementPolicy::kDisabled;
313 
314   Runtime* runtime = Runtime::Current();
315 
316   if ((runtime_flags & DISABLE_VERIFIER) != 0) {
317     runtime->DisableVerifier();
318     runtime_flags &= ~DISABLE_VERIFIER;
319   }
320 
321   if ((runtime_flags & ONLY_USE_TRUSTED_OAT_FILES) == 0 && !is_system_server) {
322     runtime->GetOatFileManager().ClearOnlyUseTrustedOatFiles();
323   }
324   runtime_flags &= ~ONLY_USE_TRUSTED_OAT_FILES;
325 
326   api_enforcement_policy = hiddenapi::EnforcementPolicyFromInt(
327       (runtime_flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) >> API_ENFORCEMENT_POLICY_SHIFT);
328   runtime_flags &= ~HIDDEN_API_ENFORCEMENT_POLICY_MASK;
329 
330   if ((runtime_flags & DISABLE_TEST_API_ENFORCEMENT_POLICY) != 0u) {
331     runtime->SetTestApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kDisabled);
332   } else {
333     runtime->SetTestApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled);
334   }
335   runtime_flags &= ~DISABLE_TEST_API_ENFORCEMENT_POLICY;
336 
337   bool profile_system_server = (runtime_flags & PROFILE_SYSTEM_SERVER) == PROFILE_SYSTEM_SERVER;
338   runtime_flags &= ~PROFILE_SYSTEM_SERVER;
339 
340   runtime->SetLoadAppImageStartupCacheEnabled(
341       (runtime_flags & USE_APP_IMAGE_STARTUP_CACHE) != 0u);
342   runtime_flags &= ~USE_APP_IMAGE_STARTUP_CACHE;
343 
344   if (runtime_flags != 0) {
345     LOG(ERROR) << StringPrintf("Unknown bits set in runtime_flags: %#x", runtime_flags);
346   }
347 
348   runtime->GetHeap()->PostForkChildAction(thread);
349 
350   // Setup an app startup complete task in case the app doesn't notify it
351   // through VMRuntime::notifyStartupCompleted.
352   static constexpr uint64_t kMaxAppStartupTimeNs = MsToNs(5000);  // 5 seconds
353   runtime->GetHeap()->AddHeapTask(new StartupCompletedTask(NanoTime() + kMaxAppStartupTimeNs));
354 
355   if (runtime->GetJit() != nullptr) {
356     if (!is_system_server) {
357       // System server already called the JIT cache post fork action in `nativePostForkSystemServer`.
358       runtime->GetJit()->GetCodeCache()->PostForkChildAction(
359           /* is_system_server= */ false, is_zygote);
360     }
361     // This must be called after EnableDebugFeatures.
362     runtime->GetJit()->PostForkChildAction(is_system_server, is_zygote);
363   }
364 
365   // Update tracing.
366   if (Trace::GetMethodTracingMode() != TracingMode::kTracingInactive) {
367     Trace::TraceOutputMode output_mode = Trace::GetOutputMode();
368     Trace::TraceMode trace_mode = Trace::GetMode();
369     size_t buffer_size = Trace::GetBufferSize();
370     int flags = Trace::GetFlags();
371     int interval = Trace::GetIntervalInMillis();
372 
373     // Just drop it.
374     Trace::Abort();
375 
376     // Only restart if it was streaming mode.
377     // TODO: Expose buffer size, so we can also do file mode.
378     if (output_mode == Trace::TraceOutputMode::kStreaming) {
379       static constexpr size_t kMaxProcessNameLength = 100;
380       char name_buf[kMaxProcessNameLength] = {};
381       int rc = pthread_getname_np(pthread_self(), name_buf, kMaxProcessNameLength);
382       std::string proc_name;
383 
384       if (rc == 0) {
385           // On success use the pthread name.
386           proc_name = name_buf;
387       }
388 
389       if (proc_name.empty() || proc_name == "zygote" || proc_name == "zygote64") {
390         // Either no process name, or the name hasn't been changed, yet. Just use pid.
391         pid_t pid = getpid();
392         proc_name = StringPrintf("%u", static_cast<uint32_t>(pid));
393       }
394 
395       const char* path = kIsTargetBuild ? "/data/misc/trace" : "/tmp";
396       std::string trace_file = StringPrintf("%s/%s.trace.bin", path, proc_name.c_str());
397       Trace::Start(trace_file.c_str(),
398                    buffer_size,
399                    flags,
400                    output_mode,
401                    trace_mode,
402                    interval);
403       if (thread->IsExceptionPending()) {
404         ScopedObjectAccess soa(env);
405         thread->ClearException();
406       }
407     }
408   }
409 
410   bool do_hidden_api_checks = api_enforcement_policy != hiddenapi::EnforcementPolicy::kDisabled;
411   DCHECK(!(is_system_server && do_hidden_api_checks))
412       << "SystemServer should be forked with EnforcementPolicy::kDisable";
413   DCHECK(!(is_zygote && do_hidden_api_checks))
414       << "Child zygote processes should be forked with EnforcementPolicy::kDisable";
415   runtime->SetHiddenApiEnforcementPolicy(api_enforcement_policy);
416   runtime->SetDedupeHiddenApiWarnings(true);
417   if (api_enforcement_policy != hiddenapi::EnforcementPolicy::kDisabled &&
418       runtime->GetHiddenApiEventLogSampleRate() != 0) {
419     // Hidden API checks are enabled, and we are sampling access for the event log. Initialize the
420     // random seed, to ensure the sampling is actually random. We do this post-fork, as doing it
421     // pre-fork would result in the same sequence for every forked process.
422     std::srand(static_cast<uint32_t>(NanoTime()));
423   }
424 
425   if (instruction_set != nullptr && !is_system_server) {
426     ScopedUtfChars isa_string(env, instruction_set);
427     InstructionSet isa = GetInstructionSetFromString(isa_string.c_str());
428     Runtime::NativeBridgeAction action = Runtime::NativeBridgeAction::kUnload;
429     if (isa != InstructionSet::kNone && isa != kRuntimeISA) {
430       action = Runtime::NativeBridgeAction::kInitialize;
431     }
432     runtime->InitNonZygoteOrPostFork(env, is_system_server, is_zygote, action, isa_string.c_str());
433   } else {
434     runtime->InitNonZygoteOrPostFork(
435         env,
436         is_system_server,
437         is_zygote,
438         Runtime::NativeBridgeAction::kUnload,
439         /*isa=*/ nullptr,
440         profile_system_server);
441   }
442 }
443 
ZygoteHooks_startZygoteNoThreadCreation(JNIEnv * env ATTRIBUTE_UNUSED,jclass klass ATTRIBUTE_UNUSED)444 static void ZygoteHooks_startZygoteNoThreadCreation(JNIEnv* env ATTRIBUTE_UNUSED,
445                                                     jclass klass ATTRIBUTE_UNUSED) {
446   Runtime::Current()->SetZygoteNoThreadSection(true);
447 }
448 
ZygoteHooks_stopZygoteNoThreadCreation(JNIEnv * env ATTRIBUTE_UNUSED,jclass klass ATTRIBUTE_UNUSED)449 static void ZygoteHooks_stopZygoteNoThreadCreation(JNIEnv* env ATTRIBUTE_UNUSED,
450                                                    jclass klass ATTRIBUTE_UNUSED) {
451   Runtime::Current()->SetZygoteNoThreadSection(false);
452 }
453 
ZygoteHooks_nativeZygoteLongSuspendOk(JNIEnv * env ATTRIBUTE_UNUSED,jclass klass ATTRIBUTE_UNUSED)454 static jboolean ZygoteHooks_nativeZygoteLongSuspendOk(JNIEnv* env ATTRIBUTE_UNUSED,
455                                                     jclass klass ATTRIBUTE_UNUSED) {
456   // Indefinite thread suspensions are not OK if we're supposed to be JIT-compiling for other
457   // processes.  We only care about JIT compilation that affects other processes.  The zygote
458   // itself doesn't run appreciable amounts of Java code when running single-threaded, so
459   // suspending the JIT in non-jit-zygote mode is OK.
460   // TODO: Make this potentially return true once we're done with JIT compilation in JIT Zygote.
461   // Only called in zygote. Thus static is OK here.
462   static bool isJitZygote = jit::Jit::InZygoteUsingJit();
463   static bool explicitlyDisabled = Runtime::Current()->IsJavaZygoteForkLoopRequired();
464   return (isJitZygote || explicitlyDisabled) ? JNI_FALSE : JNI_TRUE;
465 }
466 
467 
468 static JNINativeMethod gMethods[] = {
469   NATIVE_METHOD(ZygoteHooks, nativePreFork, "()J"),
470   NATIVE_METHOD(ZygoteHooks, nativePostZygoteFork, "()V"),
471   NATIVE_METHOD(ZygoteHooks, nativePostForkSystemServer, "(I)V"),
472   NATIVE_METHOD(ZygoteHooks, nativePostForkChild, "(JIZZLjava/lang/String;)V"),
473   NATIVE_METHOD(ZygoteHooks, nativeZygoteLongSuspendOk, "()Z"),
474   NATIVE_METHOD(ZygoteHooks, startZygoteNoThreadCreation, "()V"),
475   NATIVE_METHOD(ZygoteHooks, stopZygoteNoThreadCreation, "()V"),
476 };
477 
register_dalvik_system_ZygoteHooks(JNIEnv * env)478 void register_dalvik_system_ZygoteHooks(JNIEnv* env) {
479   REGISTER_NATIVE_METHODS("dalvik/system/ZygoteHooks");
480 }
481 
482 }  // namespace art
483