Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
188eb8f
fixup! support for per-app dynamic code loading restrictions
muhomorr Jun 12, 2026
af53bfd
Revert "match the initial call stack between exec and zygote spawning"
muhomorr Jun 12, 2026
6211b12
Revert "exec spawning: add workaround for late init of ART userfaultf…
muhomorr Jun 12, 2026
8ac7055
Revert "exec spawning: support disabling hardened_malloc and extended…
muhomorr Jun 12, 2026
78965f1
Revert "exec spawning: don't close the binder connection when the app…
muhomorr Jun 12, 2026
480df60
Revert "add a wrapper for execveat(2)"
muhomorr Jun 12, 2026
0c93020
remove the previous exec spawning implementation
muhomorr Jun 12, 2026
cf94099
fixup! AppBindArgs: infrastructure for passing extra args to app proc…
muhomorr Jun 12, 2026
9b6c191
fixup! exec spawning: support runtime resource overlays
muhomorr Jun 12, 2026
c8d4d09
gosps: add USE_EXEC_SPAWNING flags
muhomorr Jun 12, 2026
5e5cda3
add exec spawning implementation
muhomorr Jun 12, 2026
6c6f222
refactor zygote infrastructure to support arbitrary number of zygotes
muhomorr Jun 12, 2026
2d1e1b6
add compat zygote instance which uses scudo instead of hardened_malloc
muhomorr Jun 12, 2026
14d1513
add GosCompatSecureSpawnTests
inthewaves Jun 12, 2026
26163a3
adjust GosCompatSecureSpawnTests to exec spawning changes
muhomorr Jun 12, 2026
346244e
fixup! add base class for complex per-app switches
muhomorr Jun 12, 2026
82c56ce
fixup! add per-app setting for hardened_malloc and extended VA space
muhomorr Jun 12, 2026
6321859
fixup! add connectivity checks setting and its migration from Setting…
muhomorr Jun 12, 2026
e30221d
fixup! add exec spawning implementation
muhomorr Jun 12, 2026
92b6c5a
fixup! gosps: add USE_EXEC_SPAWNING flags
muhomorr Jun 13, 2026
8a9dd14
fixup! refactor zygote infrastructure to support arbitrary number of …
muhomorr Jun 13, 2026
43dbbca
fixup! add compat zygote instance which uses scudo instead of hardene…
muhomorr Jun 13, 2026
6c983a6
fixup! add exec spawning implementation
muhomorr Jun 13, 2026
8ce048e
fixup! add exec spawning implementation
muhomorr Jun 13, 2026
7e91067
fixup! add compat zygote instance which uses scudo instead of hardene…
muhomorr Jun 13, 2026
f5ac3d7
fixup! add compat zygote instance which uses scudo instead of hardene…
muhomorr Jun 13, 2026
e0acbf0
fixup! add exec spawning implementation
muhomorr Jun 13, 2026
837ec57
fixup! add exec spawning implementation
muhomorr Jun 13, 2026
aa8c224
fixup! add exec spawning implementation
muhomorr Jun 13, 2026
2d9b0db
fixup! add exec spawning implementation
muhomorr Jun 13, 2026
22141b7
fixup! add exec spawning implementation
muhomorr Jun 13, 2026
3a5a33d
fixup! add exec spawning implementation
muhomorr Jun 13, 2026
ea6744b
fixup! add exec spawning implementation
muhomorr Jun 13, 2026
486c24c
fixup! add exec spawning implementation
muhomorr Jun 13, 2026
3063d1a
fixup! add exec spawning implementation
muhomorr Jun 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 3 additions & 10 deletions cmds/app_process/app_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,8 @@ class AppRuntime : public AndroidRuntime
AndroidRuntime* ar = AndroidRuntime::getRuntime();
ar->callMain(mClassName, mClass, mArgs);

if (mClassName != "com.android.internal.os.ExecInit") {
IPCThreadState::self()->stopProcess();
hardware::IPCThreadState::self()->stopProcess();
}
IPCThreadState::self()->stopProcess();
hardware::IPCThreadState::self()->stopProcess();
}

virtual void onZygoteInit()
Expand Down Expand Up @@ -337,12 +335,7 @@ int main(int argc, char* const argv[])
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (!className.empty()) {
const char* isExecSpawning = getenv("IS_EXEC_SPAWNED_APP_PROCESS");
if (isExecSpawning != nullptr && strcmp(isExecSpawning, "1") == 0) {
runtime.start("com.android.internal.os.ZygoteInit", args, false);
} else {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
}
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
Expand Down
4 changes: 3 additions & 1 deletion core/java/android/app/ActivityThread.java
Original file line number Diff line number Diff line change
Expand Up @@ -5545,6 +5545,7 @@ private void handleCreateService(CreateServiceData data) {
cl = packageInfo.getClassLoader();
}
{
com.android.internal.os.ExecSpawning.handleAppZygotePreload(data.info, packageInfo);
String className = data.info.name;
service = ActivityThreadHooks.instantiateService(className);
if (service == null) {
Expand Down Expand Up @@ -7855,6 +7856,8 @@ private String getInstrumentationLibrary(ApplicationInfo appInfo, Instrumentatio
@UnsupportedAppUsage
@RavenwoodThrow(comment = "See ActivityThread_ravenwood for initialization on Ravenwood")
private void handleBindApplication(AppBindData data) {
final Bundle extraAppBindArgs = ActivityThreadHooks.onBind(data);

mDdmSyncStageUpdater.next(Stage.Bind);

// Register the UI Thread as a sensitive thread to the runtime.
Expand Down Expand Up @@ -8049,7 +8052,6 @@ private void handleBindApplication(AppBindData data) {
final IActivityManager mgr = ActivityManager.getService();
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
mConfigurationController.updateLocaleListFromAppContext(appContext);
final Bundle extraAppBindArgs = ActivityThreadHooks.onBind(appContext, data);

// Initialize the default http proxy in this process.
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Setup proxies");
Expand Down
10 changes: 5 additions & 5 deletions core/java/android/app/ActivityThreadHooks.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package android.app;

import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.GosPackageState;
import android.content.pm.SrtPermissions;
import android.content.res.AssetManager;
import android.ext.dcl.DynCodeLoading;
import android.location.HookedLocationManager;
import android.os.Bundle;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;

import com.android.internal.app.ContactScopes;
import com.android.internal.app.StorageScopesAppHooks;
Expand All @@ -23,7 +21,7 @@ class ActivityThreadHooks {

// called after the initial app context is constructed
// ActivityThread.handleBindApplication
static Bundle onBind(Context appContext, ActivityThread.AppBindData appBindData) {
static Bundle onBind(ActivityThread.AppBindData appBindData) {
Bundle args = appBindData.extraArgs;
Objects.requireNonNull(args, "args bundle is null");

Expand All @@ -32,7 +30,9 @@ static Bundle onBind(Context appContext, ActivityThread.AppBindData appBindData)
}
called = true;

AppGlobals.setInitialPackageId(appContext.getApplicationInfo().ext().getPackageId());
AssetManager.systemIdmapPaths_ = args.getStringArray(AppBindArgs.KEY_SYSTEM_IDMAP_PATHS);

AppGlobals.setInitialPackageId(appBindData.appInfo.ext().getPackageId());

int[] flags = Objects.requireNonNull(args.getIntArray(AppBindArgs.KEY_FLAGS_ARRAY));

Expand Down
1 change: 1 addition & 0 deletions core/java/android/app/AppBindArgs.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/** @hide */
public interface AppBindArgs {
String KEY_GOS_PACKAGE_STATE = "gosPs";
String KEY_SYSTEM_IDMAP_PATHS = "idmapPaths";
String KEY_FLAGS_ARRAY = "flagsArr";

int FLAGS_IDX_SPECIAL_RUNTIME_PERMISSIONS = 0;
Expand Down
2 changes: 0 additions & 2 deletions core/java/android/app/IActivityManager.aidl
Original file line number Diff line number Diff line change
Expand Up @@ -1051,8 +1051,6 @@ interface IActivityManager {
@EnforcePermission("INTERACT_ACROSS_USERS_FULL")
IBinder refreshIntentCreatorToken(in Intent intent);

String[] getSystemIdmapPaths();

oneway void showDynCodeLoadingNotification(int type, String pkgName, @nullable String path,
in List<String> reportBody, String denialType);

Expand Down
4 changes: 4 additions & 0 deletions core/java/android/content/pm/GosPackageStateFlag.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public interface GosPackageStateFlag {
/** @hide */ int PLAY_INTEGRITY_API_USED_AT_LEAST_ONCE = 26;
/** @hide */ int SUPPRESS_PLAY_INTEGRITY_API_NOTIF = 27;
/** @hide */ int BLOCK_PLAY_INTEGRITY_API = 28;
/** @hide */ int USE_EXEC_SPAWNING_NON_DEFAULT = 29;
/** @hide */ int USE_EXEC_SPAWNING = 30;
Comment thread
muhomorr marked this conversation as resolved.

/** @hide */
@IntDef(value = {
Expand Down Expand Up @@ -64,6 +66,8 @@ public interface GosPackageStateFlag {
PLAY_INTEGRITY_API_USED_AT_LEAST_ONCE,
SUPPRESS_PLAY_INTEGRITY_API_NOTIF,
BLOCK_PLAY_INTEGRITY_API,
USE_EXEC_SPAWNING_NON_DEFAULT,
USE_EXEC_SPAWNING,
})
@Retention(RetentionPolicy.SOURCE)
@interface Enum {}
Expand Down
17 changes: 5 additions & 12 deletions core/java/android/content/res/AssetManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.om.OverlayConfig;
import com.android.internal.os.ExecInit;
import com.android.internal.ravenwood.RavenwoodHelperBridge;

import java.io.FileDescriptor;
Expand Down Expand Up @@ -302,17 +301,11 @@ public static void createSystemAssetsInZygoteLocked(boolean reinitialize,
// When exec-based spawning in used, in-memory cache of assets is lost, and the spawned
// process is unable to recreate it, since it's not allowed to create idmaps.
//
// As a workaround, ask the ActivityManager to return paths of cached idmaps and use
// them directly. ActivityManager runs in system_server, which always uses zygote-based
// spawning.
if (ExecInit.isExecSpawned) {
try {
systemIdmapPaths = ActivityManager.getService().getSystemIdmapPaths();
Objects.requireNonNull(systemIdmapPaths);
} catch (Throwable t) {
Log.e(TAG, "unable to retrieve systemIdmapPaths", t);
systemIdmapPaths = new String[0];
}
// To resolve this issue, idmap paths are passed from system_server via AppBindArgs.
// system_server always uses zygote-based spawning.
systemIdmapPaths = systemIdmapPaths_;
if (systemIdmapPaths != null) {
Log.d(TAG, "reusing systemIdmapPaths");
} else {
systemIdmapPaths = OverlayConfig.getZygoteInstance().createImmutableFrameworkIdmapsInZygote();
systemIdmapPaths_ = systemIdmapPaths;
Expand Down
2 changes: 2 additions & 0 deletions core/java/android/ext/settings/ConnChecksSetting.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package android.ext.settings;

import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.SystemProperties;

/** @hide */
Expand All @@ -23,6 +24,7 @@ public class ConnChecksSetting {
ConnChecksSetting.VAL_GRAPHENEOS, ConnChecksSetting.VAL_STANDARD, ConnChecksSetting.VAL_DISABLED
);

@UnsupportedAppUsage
public static int get() {
return SYS_PROP.get();
}
Expand Down
1 change: 1 addition & 0 deletions core/java/android/ext/settings/app/AppSwitch.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public abstract class AppSwitch {
public static final int IR_IS_DEBUGGABLE_APP = 5;
public static final int IR_EXPLOIT_PROTECTION_COMPAT_MODE = 6;
public static final int IR_REQUIRED_BY_HARDENED_MALLOC = 7;
public static final int IR_REQUIRED_BY_ZYGOTE_SPAWNING = 8;

// default value reasons
public static final int DVR_UNKNOWN = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ private AswRestrictMemoryDynCodeLoading() {
gosPsFlagNonDefault = GosPackageStateFlag.RESTRICT_MEMORY_DYN_CODE_LOADING_NON_DEFAULT;
gosPsFlag = GosPackageStateFlag.RESTRICT_MEMORY_DYN_CODE_LOADING;
gosPsFlagSuppressNotif = GosPackageStateFlag.RESTRICT_MEMORY_DYN_CODE_LOADING_SUPPRESS_NOTIF;
compatChangeToDisableHardening = AppCompatProtos.ALLOW_MEMORY_DYN_CODE_EXEC;
compatChangeToDisableHardening = AppCompatProtos.ALLOW_MEMORY_DYN_CODE_LOADING;
}

private static volatile ArraySet<String> allowedSystemPkgs;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ private AswRestrictStorageDynCodeLoading() {
gosPsFlagNonDefault = GosPackageStateFlag.RESTRICT_STORAGE_DYN_CODE_LOADING_NON_DEFAULT;
gosPsFlag = GosPackageStateFlag.RESTRICT_STORAGE_DYN_CODE_LOADING;
gosPsFlagSuppressNotif = GosPackageStateFlag.RESTRICT_STORAGE_DYN_CODE_LOADING_SUPPRESS_NOTIF;
compatChangeToDisableHardening = AppCompatProtos.ALLOW_STORAGE_DYN_CODE_EXEC;
compatChangeToDisableHardening = AppCompatProtos.ALLOW_STORAGE_DYN_CODE_LOADING;
}

private static volatile ArraySet<String> allowedSystemPkgs;
Expand Down
37 changes: 37 additions & 0 deletions core/java/android/ext/settings/app/AswUseExecSpawning.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package android.ext.settings.app;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.GosPackageState;
import android.content.pm.GosPackageStateFlag;
import android.ext.settings.ExtSettings;

import com.android.server.os.nano.AppCompatProtos;

/** @hide */
public class AswUseExecSpawning extends AppSwitch {
public static final AswUseExecSpawning I = new AswUseExecSpawning();

private AswUseExecSpawning() {
gosPsFlag = GosPackageStateFlag.USE_EXEC_SPAWNING;
gosPsFlagNonDefault = GosPackageStateFlag.USE_EXEC_SPAWNING_NON_DEFAULT;
compatChangeToDisableHardening = AppCompatProtos.USE_ZYGOTE_SPAWNING;
}

@Override
public Boolean getImmutableValue(Context ctx, int userId, ApplicationInfo appInfo,
GosPackageState ps, StateInfo si) {
if (ps.hasFlag(GosPackageStateFlag.ENABLE_EXPLOIT_PROTECTION_COMPAT_MODE)) {
si.immutabilityReason = IR_EXPLOIT_PROTECTION_COMPAT_MODE;
return Boolean.FALSE;
}

return null;
}

@Override
protected boolean getDefaultValueInner(Context ctx, int userId, ApplicationInfo appInfo,
GosPackageState ps, StateInfo si) {
return ExtSettings.EXEC_SPAWNING.get();
}
}
41 changes: 36 additions & 5 deletions core/java/android/ext/settings/app/AswUseExtendedVaSpace.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.GosPackageState;
import android.content.pm.GosPackageStateFlag;
import android.os.Build;

import com.android.server.os.nano.AppCompatProtos;

import java.util.Objects;

import dalvik.system.VMRuntime;

/** @hide */
Expand All @@ -24,23 +27,51 @@ public Boolean getImmutableValue(Context ctx, int userId, ApplicationInfo appInf
GosPackageState ps, StateInfo si) {
if (AswUseHardenedMalloc.I.get(ctx, userId, appInfo, ps)) {
si.immutabilityReason = IR_REQUIRED_BY_HARDENED_MALLOC;
return true;
return Boolean.TRUE;
}

String primaryAbi = appInfo.primaryCpuAbi;
if (primaryAbi != null && !VMRuntime.is64BitAbi(primaryAbi)) {
si.immutabilityReason = IR_NON_64_BIT_NATIVE_CODE;
return false;
if (primaryAbi != null) {
String isa = Objects.requireNonNull(VMRuntime.getInstructionSet(primaryAbi));
if (!VMRuntime.is64BitInstructionSet(isa)) {
si.immutabilityReason = IR_NON_64_BIT_NATIVE_CODE;
return Boolean.FALSE;
}
if (!isAvailable(isa)) {
return Boolean.TRUE;
}
}

if (!isAvailable()) {
return Boolean.TRUE;
}

if (!AswUseExecSpawning.I.get(ctx, userId, appInfo, ps)) {
// When zygote spawning is used, extended VA space can't be used without also using
// hardened_malloc. This is a consequence of having 2 zygotes:
// - primary zygote with hardened_malloc and extended VA space
// - compat zygote with scudo and, on arm64, 39-bit VA space
si.immutabilityReason = IR_REQUIRED_BY_ZYGOTE_SPAWNING;
return Boolean.FALSE;
}

if (ps.hasFlag(GosPackageStateFlag.ENABLE_EXPLOIT_PROTECTION_COMPAT_MODE)) {
si.immutabilityReason = IR_EXPLOIT_PROTECTION_COMPAT_MODE;
return false;
return Boolean.FALSE;
}

return null;
}

public static boolean isAvailable() {
return isAvailable(VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]));
}

public static boolean isAvailable(String isa) {
// disabling extended VA space is supported only on arm64
return isa.equals("arm64");
}

@Override
protected boolean getDefaultValueInner(Context ctx, int userId, ApplicationInfo appInfo,
GosPackageState ps, StateInfo si) {
Expand Down
7 changes: 0 additions & 7 deletions core/java/android/ext/settings/app/AswUseHardenedMalloc.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,6 @@ public Boolean getImmutableValue(Context ctx, int userId, ApplicationInfo appInf
return false;
}

if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
// turning off hardened_malloc requires exec spawning, which is always disabled for
// debuggable apps
si.immutabilityReason = IR_IS_DEBUGGABLE_APP;
return true;
}

if (appInfo.isSystemApp()) {
si.immutabilityReason = IR_IS_SYSTEM_APP;
return true;
Expand Down
Loading