summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/AppZygote.java87
-rw-r--r--core/java/android/os/ChildZygoteProcess.java38
-rw-r--r--core/java/android/os/ZygoteProcess.java2
-rw-r--r--core/java/android/os/flags.aconfig7
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java11
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;