Loading core/java/android/os/AppZygote.java +86 −1 Original line number Diff line number Diff line Loading @@ -16,15 +16,22 @@ package android.os; import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.ApplicationInfo; import android.content.pm.ProcessInfo; import android.util.Log; import android.util.Pair; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.Zygote; import dalvik.system.VMRuntime; import java.util.Map; /** * AppZygote is responsible for interfacing with an application-specific zygote. * Loading Loading @@ -94,12 +101,90 @@ public class AppZygote { return mAppInfo; } /** * Start a new process. * * <p>Wrap ZygoteProcess.start with retry logic. * * @param processClass The class to use as the process's main entry * point. * @param niceName A more readable name to use for the process. * @param uid The user-id under which the process will run. * @param gids Additional group-ids associated with the process. * @param runtimeFlags Additional flags. * @param targetSdkVersion The target SDK version for the app. * @param seInfo null-ok SELinux information for the new process. * @param abi non-null the ABI this app should be started with. * @param instructionSet null-ok the instruction set to use. * @param appDataDir null-ok the data directory of the app. * @param packageName null-ok the name of the package this process belongs to. * @param isTopApp Whether the process starts for high priority application. * @param disabledCompatChanges null-ok list of disabled compat changes for the process being * started. * @param pkgDataInfoMap Map from related package names to private data directory * volume UUID and inode number. * @param allowlistedDataInfoList Map from allowlisted package names to private data directory * volume UUID and inode number. * @param zygoteArgs Additional arguments to supply to the Zygote process. * @return An object that describes the result of the attempt to start the process. * @throws RuntimeException on fatal start failure */ public final Process.ProcessStartResult startProcess(@NonNull final String processClass, final String niceName, int uid, @Nullable int[] gids, int runtimeFlags, int mountExternal, int targetSdkVersion, @Nullable String seInfo, @NonNull String abi, @Nullable String instructionSet, @Nullable String appDataDir, @Nullable String packageName, boolean isTopApp, @Nullable long[] disabledCompatChanges, @Nullable Map<String, Pair<String, Long>> pkgDataInfoMap, @Nullable Map<String, Pair<String, Long>> allowlistedDataInfoList, @Nullable String[] zygoteArgs) { try { return getProcess().start(processClass, niceName, uid, uid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, null, packageName, /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp, disabledCompatChanges, pkgDataInfoMap, allowlistedDataInfoList, false, false, false, zygoteArgs); } catch (RuntimeException e) { if (!Flags.appZygoteRetryStart()) { throw e; } final boolean zygote_dead = getProcess().isDead(); if (!zygote_dead) { throw e; // Zygote process is alive. Do nothing. } } // Retry here if the previous start fails. Log.w(LOG_TAG, "retry starting process " + niceName); stopZygote(); return getProcess().start(processClass, niceName, uid, uid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, null, packageName, /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp, disabledCompatChanges, pkgDataInfoMap, allowlistedDataInfoList, false, false, false, zygoteArgs); } @GuardedBy("mLock") private void stopZygoteLocked() { if (mZygote != null) { mZygote.close(); // use killProcessGroup() here, so we kill all untracked children as well. if (!mZygote.isDead()) { Process.killProcessGroup(mZygoteUid, mZygote.getPid()); } mZygote = null; } } Loading core/java/android/os/ChildZygoteProcess.java +37 −1 Original line number Diff line number Diff line Loading @@ -17,6 +17,10 @@ package android.os; import android.net.LocalSocketAddress; import android.system.ErrnoException; import android.system.Os; import java.util.concurrent.atomic.AtomicBoolean; /** * Represents a connection to a child-zygote process. A child-zygote is spawend from another Loading @@ -30,9 +34,23 @@ public class ChildZygoteProcess extends ZygoteProcess { */ private final int mPid; ChildZygoteProcess(LocalSocketAddress socketAddress, int pid) { /** * The UID of the child zygote process. */ private final int mUid; /** * If this zygote process was dead; */ private AtomicBoolean mDead; ChildZygoteProcess(LocalSocketAddress socketAddress, int pid, int uid) { super(socketAddress, null); mPid = pid; mUid = uid; mDead = new AtomicBoolean(false); } /** Loading @@ -41,4 +59,22 @@ public class ChildZygoteProcess extends ZygoteProcess { public int getPid() { return mPid; } /** * Check if child-zygote process is dead */ public boolean isDead() { if (mDead.get()) { return true; } try { if (Os.stat("/proc/" + mPid).st_uid == mUid) { return false; } } catch (ErrnoException e) { // Do nothing, it's dead. } mDead.set(true); return true; } } core/java/android/os/ZygoteProcess.java +1 −1 Original line number Diff line number Diff line Loading @@ -1319,6 +1319,6 @@ public class ZygoteProcess { throw new RuntimeException("Starting child-zygote through Zygote failed", ex); } return new ChildZygoteProcess(serverAddress, result.pid); return new ChildZygoteProcess(serverAddress, result.pid, uid); } } core/java/android/os/flags.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -149,6 +149,13 @@ flag { is_exported: true } flag { name: "app_zygote_retry_start" namespace: "arc_next" description: "Guard the new added retry logic in app zygote." bug: "361799815" } flag { name: "battery_part_status_api" is_exported: true Loading services/core/java/com/android/server/am/ProcessList.java +5 −6 Original line number Diff line number Diff line Loading @@ -2553,13 +2553,12 @@ public final class ProcessList { final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app); // We can't isolate app data and storage data as parent zygote already did that. startResult = appZygote.getProcess().start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, startResult = appZygote.startProcess(entryPoint, app.processName, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp, app.getDisabledCompatChanges(), pkgDataInfoMap, allowlistedAppDataInfoMap, false, false, false, app.info.dataDir, app.info.packageName, isTopApp, app.getDisabledCompatChanges(), pkgDataInfoMap, allowlistedAppDataInfoMap, new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()}); } else { regularZygote = true; Loading Loading
core/java/android/os/AppZygote.java +86 −1 Original line number Diff line number Diff line Loading @@ -16,15 +16,22 @@ package android.os; import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.ApplicationInfo; import android.content.pm.ProcessInfo; import android.util.Log; import android.util.Pair; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.Zygote; import dalvik.system.VMRuntime; import java.util.Map; /** * AppZygote is responsible for interfacing with an application-specific zygote. * Loading Loading @@ -94,12 +101,90 @@ public class AppZygote { return mAppInfo; } /** * Start a new process. * * <p>Wrap ZygoteProcess.start with retry logic. * * @param processClass The class to use as the process's main entry * point. * @param niceName A more readable name to use for the process. * @param uid The user-id under which the process will run. * @param gids Additional group-ids associated with the process. * @param runtimeFlags Additional flags. * @param targetSdkVersion The target SDK version for the app. * @param seInfo null-ok SELinux information for the new process. * @param abi non-null the ABI this app should be started with. * @param instructionSet null-ok the instruction set to use. * @param appDataDir null-ok the data directory of the app. * @param packageName null-ok the name of the package this process belongs to. * @param isTopApp Whether the process starts for high priority application. * @param disabledCompatChanges null-ok list of disabled compat changes for the process being * started. * @param pkgDataInfoMap Map from related package names to private data directory * volume UUID and inode number. * @param allowlistedDataInfoList Map from allowlisted package names to private data directory * volume UUID and inode number. * @param zygoteArgs Additional arguments to supply to the Zygote process. * @return An object that describes the result of the attempt to start the process. * @throws RuntimeException on fatal start failure */ public final Process.ProcessStartResult startProcess(@NonNull final String processClass, final String niceName, int uid, @Nullable int[] gids, int runtimeFlags, int mountExternal, int targetSdkVersion, @Nullable String seInfo, @NonNull String abi, @Nullable String instructionSet, @Nullable String appDataDir, @Nullable String packageName, boolean isTopApp, @Nullable long[] disabledCompatChanges, @Nullable Map<String, Pair<String, Long>> pkgDataInfoMap, @Nullable Map<String, Pair<String, Long>> allowlistedDataInfoList, @Nullable String[] zygoteArgs) { try { return getProcess().start(processClass, niceName, uid, uid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, null, packageName, /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp, disabledCompatChanges, pkgDataInfoMap, allowlistedDataInfoList, false, false, false, zygoteArgs); } catch (RuntimeException e) { if (!Flags.appZygoteRetryStart()) { throw e; } final boolean zygote_dead = getProcess().isDead(); if (!zygote_dead) { throw e; // Zygote process is alive. Do nothing. } } // Retry here if the previous start fails. Log.w(LOG_TAG, "retry starting process " + niceName); stopZygote(); return getProcess().start(processClass, niceName, uid, uid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, null, packageName, /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp, disabledCompatChanges, pkgDataInfoMap, allowlistedDataInfoList, false, false, false, zygoteArgs); } @GuardedBy("mLock") private void stopZygoteLocked() { if (mZygote != null) { mZygote.close(); // use killProcessGroup() here, so we kill all untracked children as well. if (!mZygote.isDead()) { Process.killProcessGroup(mZygoteUid, mZygote.getPid()); } mZygote = null; } } Loading
core/java/android/os/ChildZygoteProcess.java +37 −1 Original line number Diff line number Diff line Loading @@ -17,6 +17,10 @@ package android.os; import android.net.LocalSocketAddress; import android.system.ErrnoException; import android.system.Os; import java.util.concurrent.atomic.AtomicBoolean; /** * Represents a connection to a child-zygote process. A child-zygote is spawend from another Loading @@ -30,9 +34,23 @@ public class ChildZygoteProcess extends ZygoteProcess { */ private final int mPid; ChildZygoteProcess(LocalSocketAddress socketAddress, int pid) { /** * The UID of the child zygote process. */ private final int mUid; /** * If this zygote process was dead; */ private AtomicBoolean mDead; ChildZygoteProcess(LocalSocketAddress socketAddress, int pid, int uid) { super(socketAddress, null); mPid = pid; mUid = uid; mDead = new AtomicBoolean(false); } /** Loading @@ -41,4 +59,22 @@ public class ChildZygoteProcess extends ZygoteProcess { public int getPid() { return mPid; } /** * Check if child-zygote process is dead */ public boolean isDead() { if (mDead.get()) { return true; } try { if (Os.stat("/proc/" + mPid).st_uid == mUid) { return false; } } catch (ErrnoException e) { // Do nothing, it's dead. } mDead.set(true); return true; } }
core/java/android/os/ZygoteProcess.java +1 −1 Original line number Diff line number Diff line Loading @@ -1319,6 +1319,6 @@ public class ZygoteProcess { throw new RuntimeException("Starting child-zygote through Zygote failed", ex); } return new ChildZygoteProcess(serverAddress, result.pid); return new ChildZygoteProcess(serverAddress, result.pid, uid); } }
core/java/android/os/flags.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -149,6 +149,13 @@ flag { is_exported: true } flag { name: "app_zygote_retry_start" namespace: "arc_next" description: "Guard the new added retry logic in app zygote." bug: "361799815" } flag { name: "battery_part_status_api" is_exported: true Loading
services/core/java/com/android/server/am/ProcessList.java +5 −6 Original line number Diff line number Diff line Loading @@ -2553,13 +2553,12 @@ public final class ProcessList { final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app); // We can't isolate app data and storage data as parent zygote already did that. startResult = appZygote.getProcess().start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, startResult = appZygote.startProcess(entryPoint, app.processName, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp, app.getDisabledCompatChanges(), pkgDataInfoMap, allowlistedAppDataInfoMap, false, false, false, app.info.dataDir, app.info.packageName, isTopApp, app.getDisabledCompatChanges(), pkgDataInfoMap, allowlistedAppDataInfoMap, new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()}); } else { regularZygote = true; Loading