diff options
| -rw-r--r-- | core/java/android/os/AppZygote.java | 87 | ||||
| -rw-r--r-- | core/java/android/os/ChildZygoteProcess.java | 38 | ||||
| -rw-r--r-- | core/java/android/os/ZygoteProcess.java | 2 | ||||
| -rw-r--r-- | core/java/android/os/flags.aconfig | 7 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/ProcessList.java | 11 |
5 files changed, 136 insertions, 9 deletions
diff --git a/core/java/android/os/AppZygote.java b/core/java/android/os/AppZygote.java index 0541a96e990e..69b6597d717a 100644 --- a/core/java/android/os/AppZygote.java +++ b/core/java/android/os/AppZygote.java @@ -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. * @@ -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. - Process.killProcessGroup(mZygoteUid, mZygote.getPid()); + if (!mZygote.isDead()) { + Process.killProcessGroup(mZygoteUid, mZygote.getPid()); + } mZygote = null; } } diff --git a/core/java/android/os/ChildZygoteProcess.java b/core/java/android/os/ChildZygoteProcess.java index 337a3e279a1a..d8f825a2ee60 100644 --- a/core/java/android/os/ChildZygoteProcess.java +++ b/core/java/android/os/ChildZygoteProcess.java @@ -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 @@ -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); } /** @@ -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; + } } diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index 73a74b2f8abc..2d487b1e77d5 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -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); } } diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig index 8b8369890d1b..b12433a73a31 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -150,6 +150,13 @@ flag { } 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 namespace: "phoenix" diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 2216f2769826..f7eaa159be30 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -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; |