/* * Copyright (C) 2006 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. */ package dalvik.system; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; import android.annotation.SystemApi; import android.icu.util.ULocale; import libcore.icu.DecimalFormatData; import libcore.icu.ICU; import java.io.File; import java.io.FileDescriptor; import java.lang.reflect.Method; import java.lang.ClassNotFoundException; import java.lang.NoSuchMethodException; import java.lang.ReflectiveOperationException; import libcore.icu.SimpleDateFormatData; import sun.util.locale.BaseLocale; import java.util.Locale; /** * Provides hooks for the zygote to call back into the runtime to perform * parent or child specific initialization.. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public final class ZygoteHooks { private static long token; private static Method enableMemoryMappedDataMethod; private static boolean inZygoteProcess = true; /** All methods are static, no need to instantiate. */ private ZygoteHooks() { } /** * Called by the zygote when starting up. It marks the point when any thread * start should be an error, as only internal daemon threads are allowed there. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static native void startZygoteNoThreadCreation(); /** * Called when the zygote begins preloading classes and data. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static void onBeginPreload() { com.android.i18n.system.ZygoteHooks.onBeginPreload(); ICU.initializeCacheInZygote(); DecimalFormatData.initializeCacheInZygote(); SimpleDateFormatData.initializeCacheInZygote(); // Look up JaCoCo on the boot classpath, if it exists. This will be used later for enabling // memory-mapped Java coverage. try { Class jacocoOfflineClass = Class.forName("org.jacoco.agent.rt.internal.Offline"); enableMemoryMappedDataMethod = jacocoOfflineClass.getMethod("enableMemoryMappedData"); } catch (ClassNotFoundException e) { // JaCoCo was not on the boot classpath, so this is not a coverage build. } catch (NoSuchMethodException e) { // Method was not found in the JaCoCo Offline class. The version of JaCoCo is not // compatible with memory-mapped coverage. throw new RuntimeException(e); } } /** * Called when the zygote has completed preloading classes and data. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static void onEndPreload() { com.android.i18n.system.ZygoteHooks.onEndPreload(); // Clone standard descriptors as originals closed / rebound during zygote post fork. FileDescriptor.in.cloneForFork(); FileDescriptor.out.cloneForFork(); FileDescriptor.err.cloneForFork(); } /** * Called after GC but before fork, it cleans stale cache entries in * BaseLocale and Locale, so to avoid the cleaning to happen in every * child process. */ private static void cleanLocaleCaches() { BaseLocale.cleanCache(); Locale.cleanCache(); // Invoke android.icu.impl.locale.BaseLocale.CACHE#cleanStaleEntries() without // using a new API on S. LocaleObjectCacheTest should verify this. // en_US locale is chosen because it's likely to be cached, and doesn't require a // new BaseLocale. new ULocale.Builder().setLanguage("en").setRegion("US").build(); } /** * Runs several special GCs to try to clean up a few generations of * softly- and final-reachable objects, along with any other garbage. * This is only useful just before a fork(). * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static void gcAndFinalize() { final VMRuntime runtime = VMRuntime.getRuntime(); /* runFinalizationSync() lets finalizers be called in Zygote, * which doesn't have a HeapWorker thread. */ System.gc(); runtime.runFinalizationSync(); cleanLocaleCaches(); System.gc(); } /** * Called by the zygote when startup is finished. It marks the point when it is * conceivable that threads would be started again, e.g., restarting daemons. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static native void stopZygoteNoThreadCreation(); /** * Called by the zygote prior to every fork. Each call to {@code preFork} * is followed by a matching call to {@link #postForkChild(int, boolean, boolean, String)} on * the child process and {@link #postForkCommon()} on both the parent and the child * process. {@code postForkCommon} is called after {@code postForkChild} in * the child process. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static void preFork() { Daemons.stop(); // At this point Daemons have been joined, but they may still be Unregister()ing. // We wait for that as part of nativePreFork(). token = nativePreFork(); } /** * Called by the zygote in the system server process after forking. This method is is called * before {@code postForkChild} for system server. * * @param runtimeFlags The flags listed in com.android.internal.os.Zygote passed to the runtime. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static void postForkSystemServer(int runtimeFlags) { nativePostForkSystemServer(runtimeFlags); } /** * Called by the zygote in the child process after every fork. * * @param runtimeFlags The runtime flags to apply to the child process. * @param isSystemServer Whether the child process is system server. * @param isChildZygote Whether the child process is a child zygote. * @param instructionSet The instruction set of the child, used to determine * whether to use a native bridge. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static void postForkChild(int runtimeFlags, boolean isSystemServer, boolean isChildZygote, String instructionSet) { nativePostForkChild(token, runtimeFlags, isSystemServer, isChildZygote, instructionSet); if (!isChildZygote) { inZygoteProcess = false; } Math.setRandomSeedInternal(System.currentTimeMillis()); // Enable memory-mapped coverage if JaCoCo is in the boot classpath. system_server is // skipped due to being persistent and having its own coverage writing mechanism. // Child zygote processes are also skipped so that file descriptors are not kept open // when the child zygote process forks again. if (!isSystemServer && !isChildZygote && enableMemoryMappedDataMethod != null) { try { enableMemoryMappedDataMethod.invoke(null); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } } } /** * Called by the zygote in both the parent and child processes after * every fork. In the child process, this method is called after * {@code postForkChild}. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static void postForkCommon() { // Notify the runtime before creating new threads. nativePostZygoteFork(); Daemons.startPostZygoteFork(); } /** * Is it safe to keep all ART daemon threads stopped indefinitely in the zygote? * The answer may change from false to true dynamically, but not in the other * direction. Only called in Zygote. * * @return {@code true} if it's safe to keep all ART daemon threads stopped * indefinitely in the zygote; and {@code false} otherwise * * @hide */ @SystemApi(client = MODULE_LIBRARIES) public static boolean isIndefiniteThreadSuspensionSafe() { return nativeZygoteLongSuspendOk(); } /** * Are we still in a zygote? * @hide */ public static boolean inZygote() { return inZygoteProcess; } // Hook for SystemServer specific early initialization post-forking. private static native void nativePostForkSystemServer(int runtimeFlags); private static native long nativePreFork(); private static native void nativePostZygoteFork(); // Hook for all child processes post forking. private static native void nativePostForkChild(long token, int runtimeFlags, boolean isSystemServer, boolean isZygote, String instructionSet); private static native boolean nativeZygoteLongSuspendOk(); }