264 lines
9.3 KiB
Java
264 lines
9.3 KiB
Java
![]() |
/*
|
||
|
* 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();
|
||
|
}
|