1 /* 2 * Copyright (C) 2006 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 package dalvik.system; 18 19 import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; 20 21 import android.annotation.SystemApi; 22 import android.icu.util.ULocale; 23 24 import libcore.icu.DecimalFormatData; 25 import libcore.icu.ICU; 26 27 import java.io.File; 28 import java.io.FileDescriptor; 29 import java.lang.reflect.Method; 30 import java.lang.ClassNotFoundException; 31 import java.lang.NoSuchMethodException; 32 import java.lang.ReflectiveOperationException; 33 import libcore.icu.SimpleDateFormatData; 34 35 import sun.util.locale.BaseLocale; 36 import java.util.Locale; 37 38 /** 39 * Provides hooks for the zygote to call back into the runtime to perform 40 * parent or child specific initialization.. 41 * 42 * @hide 43 */ 44 @SystemApi(client = MODULE_LIBRARIES) 45 public final class ZygoteHooks { 46 private static long token; 47 private static Method enableMemoryMappedDataMethod; 48 private static boolean inZygoteProcess = true; 49 50 /** All methods are static, no need to instantiate. */ ZygoteHooks()51 private ZygoteHooks() { 52 } 53 54 /** 55 * Called by the zygote when starting up. It marks the point when any thread 56 * start should be an error, as only internal daemon threads are allowed there. 57 * 58 * @hide 59 */ 60 @SystemApi(client = MODULE_LIBRARIES) startZygoteNoThreadCreation()61 public static native void startZygoteNoThreadCreation(); 62 63 /** 64 * Called when the zygote begins preloading classes and data. 65 * 66 * @hide 67 */ 68 @SystemApi(client = MODULE_LIBRARIES) onBeginPreload()69 public static void onBeginPreload() { 70 com.android.i18n.system.ZygoteHooks.onBeginPreload(); 71 72 ICU.initializeCacheInZygote(); 73 DecimalFormatData.initializeCacheInZygote(); 74 SimpleDateFormatData.initializeCacheInZygote(); 75 76 // Look up JaCoCo on the boot classpath, if it exists. This will be used later for enabling 77 // memory-mapped Java coverage. 78 try { 79 Class<?> jacocoOfflineClass = Class.forName("org.jacoco.agent.rt.internal.Offline"); 80 enableMemoryMappedDataMethod = jacocoOfflineClass.getMethod("enableMemoryMappedData"); 81 } catch (ClassNotFoundException e) { 82 // JaCoCo was not on the boot classpath, so this is not a coverage build. 83 } catch (NoSuchMethodException e) { 84 // Method was not found in the JaCoCo Offline class. The version of JaCoCo is not 85 // compatible with memory-mapped coverage. 86 throw new RuntimeException(e); 87 } 88 } 89 90 /** 91 * Called when the zygote has completed preloading classes and data. 92 * 93 * @hide 94 */ 95 @SystemApi(client = MODULE_LIBRARIES) onEndPreload()96 public static void onEndPreload() { 97 com.android.i18n.system.ZygoteHooks.onEndPreload(); 98 99 // Clone standard descriptors as originals closed / rebound during zygote post fork. 100 FileDescriptor.in.cloneForFork(); 101 FileDescriptor.out.cloneForFork(); 102 FileDescriptor.err.cloneForFork(); 103 } 104 105 /** 106 * Called after GC but before fork, it cleans stale cache entries in 107 * BaseLocale and Locale, so to avoid the cleaning to happen in every 108 * child process. 109 */ cleanLocaleCaches()110 private static void cleanLocaleCaches() { 111 BaseLocale.cleanCache(); 112 Locale.cleanCache(); 113 114 // Invoke android.icu.impl.locale.BaseLocale.CACHE#cleanStaleEntries() without 115 // using a new API on S. LocaleObjectCacheTest should verify this. 116 // en_US locale is chosen because it's likely to be cached, and doesn't require a 117 // new BaseLocale. 118 new ULocale.Builder().setLanguage("en").setRegion("US").build(); 119 } 120 121 /** 122 * Runs several special GCs to try to clean up a few generations of 123 * softly- and final-reachable objects, along with any other garbage. 124 * This is only useful just before a fork(). 125 * 126 * @hide 127 */ 128 @SystemApi(client = MODULE_LIBRARIES) gcAndFinalize()129 public static void gcAndFinalize() { 130 final VMRuntime runtime = VMRuntime.getRuntime(); 131 132 /* runFinalizationSync() lets finalizers be called in Zygote, 133 * which doesn't have a HeapWorker thread. 134 */ 135 System.gc(); 136 runtime.runFinalizationSync(); 137 cleanLocaleCaches(); 138 System.gc(); 139 } 140 141 /** 142 * Called by the zygote when startup is finished. It marks the point when it is 143 * conceivable that threads would be started again, e.g., restarting daemons. 144 * 145 * @hide 146 */ 147 @SystemApi(client = MODULE_LIBRARIES) stopZygoteNoThreadCreation()148 public static native void stopZygoteNoThreadCreation(); 149 150 /** 151 * Called by the zygote prior to every fork. Each call to {@code preFork} 152 * is followed by a matching call to {@link #postForkChild(int, boolean, boolean, String)} on 153 * the child process and {@link #postForkCommon()} on both the parent and the child 154 * process. {@code postForkCommon} is called after {@code postForkChild} in 155 * the child process. 156 * 157 * @hide 158 */ 159 @SystemApi(client = MODULE_LIBRARIES) preFork()160 public static void preFork() { 161 Daemons.stop(); 162 // At this point Daemons have been joined, but they may still be Unregister()ing. 163 // We wait for that as part of nativePreFork(). 164 token = nativePreFork(); 165 } 166 167 /** 168 * Called by the zygote in the system server process after forking. This method is is called 169 * before {@code postForkChild} for system server. 170 * 171 * @param runtimeFlags The flags listed in com.android.internal.os.Zygote passed to the runtime. 172 * 173 * @hide 174 */ 175 @SystemApi(client = MODULE_LIBRARIES) postForkSystemServer(int runtimeFlags)176 public static void postForkSystemServer(int runtimeFlags) { 177 nativePostForkSystemServer(runtimeFlags); 178 } 179 180 /** 181 * Called by the zygote in the child process after every fork. 182 * 183 * @param runtimeFlags The runtime flags to apply to the child process. 184 * @param isSystemServer Whether the child process is system server. 185 * @param isChildZygote Whether the child process is a child zygote. 186 * @param instructionSet The instruction set of the child, used to determine 187 * whether to use a native bridge. 188 * 189 * @hide 190 */ 191 @SystemApi(client = MODULE_LIBRARIES) postForkChild(int runtimeFlags, boolean isSystemServer, boolean isChildZygote, String instructionSet)192 public static void postForkChild(int runtimeFlags, boolean isSystemServer, 193 boolean isChildZygote, String instructionSet) { 194 nativePostForkChild(token, runtimeFlags, isSystemServer, isChildZygote, instructionSet); 195 if (!isChildZygote) { 196 inZygoteProcess = false; 197 } 198 199 Math.setRandomSeedInternal(System.currentTimeMillis()); 200 201 // Enable memory-mapped coverage if JaCoCo is in the boot classpath. system_server is 202 // skipped due to being persistent and having its own coverage writing mechanism. 203 // Child zygote processes are also skipped so that file descriptors are not kept open 204 // when the child zygote process forks again. 205 if (!isSystemServer && !isChildZygote && enableMemoryMappedDataMethod != null) { 206 try { 207 enableMemoryMappedDataMethod.invoke(null); 208 } catch (ReflectiveOperationException e) { 209 throw new RuntimeException(e); 210 } 211 } 212 } 213 214 /** 215 * Called by the zygote in both the parent and child processes after 216 * every fork. In the child process, this method is called after 217 * {@code postForkChild}. 218 * 219 * @hide 220 */ 221 @SystemApi(client = MODULE_LIBRARIES) postForkCommon()222 public static void postForkCommon() { 223 // Notify the runtime before creating new threads. 224 nativePostZygoteFork(); 225 Daemons.startPostZygoteFork(); 226 } 227 228 /** 229 * Is it safe to keep all ART daemon threads stopped indefinitely in the zygote? 230 * The answer may change from false to true dynamically, but not in the other 231 * direction. Only called in Zygote. 232 * 233 * @return {@code true} if it's safe to keep all ART daemon threads stopped 234 * indefinitely in the zygote; and {@code false} otherwise 235 * 236 * @hide 237 */ 238 @SystemApi(client = MODULE_LIBRARIES) isIndefiniteThreadSuspensionSafe()239 public static boolean isIndefiniteThreadSuspensionSafe() { 240 return nativeZygoteLongSuspendOk(); 241 } 242 243 /** 244 * Are we still in a zygote? 245 * @hide 246 */ inZygote()247 public static boolean inZygote() { 248 return inZygoteProcess; 249 } 250 251 // Hook for SystemServer specific early initialization post-forking. nativePostForkSystemServer(int runtimeFlags)252 private static native void nativePostForkSystemServer(int runtimeFlags); 253 nativePreFork()254 private static native long nativePreFork(); nativePostZygoteFork()255 private static native void nativePostZygoteFork(); 256 257 // Hook for all child processes post forking. nativePostForkChild(long token, int runtimeFlags, boolean isSystemServer, boolean isZygote, String instructionSet)258 private static native void nativePostForkChild(long token, int runtimeFlags, 259 boolean isSystemServer, boolean isZygote, 260 String instructionSet); 261 nativeZygoteLongSuspendOk()262 private static native boolean nativeZygoteLongSuspendOk(); 263 } 264