Merge "Fix memory flags in external services and secondary zygotes." into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
951aa29f72
@@ -17,9 +17,11 @@
|
||||
package android.os;
|
||||
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ProcessInfo;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.os.Zygote;
|
||||
|
||||
import dalvik.system.VMRuntime;
|
||||
|
||||
@@ -45,8 +47,6 @@ public class AppZygote {
|
||||
// Last UID/GID of the range the AppZygote can setuid()/setgid() to
|
||||
private final int mZygoteUidGidMax;
|
||||
|
||||
private final int mZygoteRuntimeFlags;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
/**
|
||||
@@ -57,14 +57,15 @@ public class AppZygote {
|
||||
private ChildZygoteProcess mZygote;
|
||||
|
||||
private final ApplicationInfo mAppInfo;
|
||||
private final ProcessInfo mProcessInfo;
|
||||
|
||||
public AppZygote(ApplicationInfo appInfo, int zygoteUid, int uidGidMin, int uidGidMax,
|
||||
int runtimeFlags) {
|
||||
public AppZygote(ApplicationInfo appInfo, ProcessInfo processInfo, int zygoteUid, int uidGidMin,
|
||||
int uidGidMax) {
|
||||
mAppInfo = appInfo;
|
||||
mProcessInfo = processInfo;
|
||||
mZygoteUid = zygoteUid;
|
||||
mZygoteUidGidMin = uidGidMin;
|
||||
mZygoteUidGidMax = uidGidMax;
|
||||
mZygoteRuntimeFlags = runtimeFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,13 +109,15 @@ public class AppZygote {
|
||||
String abi = mAppInfo.primaryCpuAbi != null ? mAppInfo.primaryCpuAbi :
|
||||
Build.SUPPORTED_ABIS[0];
|
||||
try {
|
||||
int runtimeFlags = Zygote.getMemorySafetyRuntimeFlagsForSecondaryZygote(
|
||||
mAppInfo, mProcessInfo);
|
||||
mZygote = Process.ZYGOTE_PROCESS.startChildZygote(
|
||||
"com.android.internal.os.AppZygoteInit",
|
||||
mAppInfo.processName + "_zygote",
|
||||
mZygoteUid,
|
||||
mZygoteUid,
|
||||
null, // gids
|
||||
mZygoteRuntimeFlags, // runtimeFlags
|
||||
runtimeFlags,
|
||||
"app_zygote", // seInfo
|
||||
abi, // abi
|
||||
abi, // acceptedAbiList
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.os.Zygote;
|
||||
|
||||
/** @hide */
|
||||
public class WebViewZygote {
|
||||
@@ -127,13 +128,15 @@ public class WebViewZygote {
|
||||
|
||||
try {
|
||||
String abi = sPackage.applicationInfo.primaryCpuAbi;
|
||||
int runtimeFlags = Zygote.getMemorySafetyRuntimeFlagsForSecondaryZygote(
|
||||
sPackage.applicationInfo, null);
|
||||
sZygote = Process.ZYGOTE_PROCESS.startChildZygote(
|
||||
"com.android.internal.os.WebViewZygoteInit",
|
||||
"webview_zygote",
|
||||
Process.WEBVIEW_ZYGOTE_UID,
|
||||
Process.WEBVIEW_ZYGOTE_UID,
|
||||
null, // gids
|
||||
0, // runtimeFlags
|
||||
runtimeFlags,
|
||||
"webview_zygote", // seInfo
|
||||
abi, // abi
|
||||
TextUtils.join(",", Build.SUPPORTED_ABIS),
|
||||
|
||||
@@ -20,13 +20,21 @@ import static android.system.OsConstants.O_CLOEXEC;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.compat.annotation.ChangeId;
|
||||
import android.compat.annotation.Disabled;
|
||||
import android.compat.annotation.EnabledAfter;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ProcessInfo;
|
||||
import android.net.Credentials;
|
||||
import android.net.LocalServerSocket;
|
||||
import android.net.LocalSocket;
|
||||
import android.os.Build;
|
||||
import android.os.FactoryTest;
|
||||
import android.os.IVold;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.Trace;
|
||||
import android.provider.DeviceConfig;
|
||||
@@ -34,6 +42,7 @@ import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.compat.IPlatformCompat;
|
||||
import com.android.internal.net.NetworkUtilsInternal;
|
||||
|
||||
import dalvik.annotation.optimization.CriticalNative;
|
||||
@@ -125,6 +134,7 @@ public final class Zygote {
|
||||
public static final int MEMORY_TAG_LEVEL_MASK = (1 << 19) | (1 << 20);
|
||||
|
||||
public static final int MEMORY_TAG_LEVEL_NONE = 0;
|
||||
|
||||
/**
|
||||
* Enable pointer tagging in this process.
|
||||
* Tags are checked during memory deallocation, but not on access.
|
||||
@@ -170,10 +180,8 @@ public final class Zygote {
|
||||
*/
|
||||
public static final int GWP_ASAN_LEVEL_ALWAYS = 1 << 22;
|
||||
|
||||
/**
|
||||
* Enable automatic zero-initialization of native heap memory allocations.
|
||||
*/
|
||||
public static final int NATIVE_HEAP_ZERO_INIT = 1 << 23;
|
||||
/** Enable automatic zero-initialization of native heap memory allocations. */
|
||||
public static final int NATIVE_HEAP_ZERO_INIT_ENABLED = 1 << 23;
|
||||
|
||||
/**
|
||||
* Enable profiling from system services. This loads profiling related plugins in ART.
|
||||
@@ -1170,4 +1178,251 @@ public final class Zygote {
|
||||
* we failed to determine the level.
|
||||
*/
|
||||
public static native int nativeCurrentTaggingLevel();
|
||||
|
||||
/**
|
||||
* Native heap allocations will now have a non-zero tag in the most significant byte.
|
||||
*
|
||||
* @see <a href="https://source.android.com/devices/tech/debug/tagged-pointers">Tagged
|
||||
* Pointers</a>
|
||||
*/
|
||||
@ChangeId
|
||||
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
|
||||
private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
|
||||
|
||||
/**
|
||||
* Native heap allocations in AppZygote process and its descendants will now have a non-zero tag
|
||||
* in the most significant byte.
|
||||
*
|
||||
* @see <a href="https://source.android.com/devices/tech/debug/tagged-pointers">Tagged
|
||||
* Pointers</a>
|
||||
*/
|
||||
@ChangeId
|
||||
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S)
|
||||
private static final long NATIVE_HEAP_POINTER_TAGGING_SECONDARY_ZYGOTE = 207557677;
|
||||
|
||||
/**
|
||||
* Enable asynchronous (ASYNC) memory tag checking in this process. This flag will only have an
|
||||
* effect on hardware supporting the ARM Memory Tagging Extension (MTE).
|
||||
*/
|
||||
@ChangeId @Disabled
|
||||
private static final long NATIVE_MEMTAG_ASYNC = 135772972; // This is a bug id.
|
||||
|
||||
/**
|
||||
* Enable synchronous (SYNC) memory tag checking in this process. This flag will only have an
|
||||
* effect on hardware supporting the ARM Memory Tagging Extension (MTE). If both
|
||||
* NATIVE_MEMTAG_ASYNC and this option is selected, this option takes preference and MTE is
|
||||
* enabled in SYNC mode.
|
||||
*/
|
||||
@ChangeId @Disabled
|
||||
private static final long NATIVE_MEMTAG_SYNC = 177438394; // This is a bug id.
|
||||
|
||||
/** Enable automatic zero-initialization of native heap memory allocations. */
|
||||
@ChangeId @Disabled
|
||||
private static final long NATIVE_HEAP_ZERO_INIT = 178038272; // This is a bug id.
|
||||
|
||||
/**
|
||||
* Enable sampled memory bug detection in the app.
|
||||
*
|
||||
* @see <a href="https://source.android.com/devices/tech/debug/gwp-asan">GWP-ASan</a>.
|
||||
*/
|
||||
@ChangeId @Disabled private static final long GWP_ASAN = 135634846; // This is a bug id.
|
||||
|
||||
private static int memtagModeToZygoteMemtagLevel(int memtagMode) {
|
||||
switch (memtagMode) {
|
||||
case ApplicationInfo.MEMTAG_ASYNC:
|
||||
return MEMORY_TAG_LEVEL_ASYNC;
|
||||
case ApplicationInfo.MEMTAG_SYNC:
|
||||
return MEMORY_TAG_LEVEL_SYNC;
|
||||
default:
|
||||
return MEMORY_TAG_LEVEL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isCompatChangeEnabled(
|
||||
long change,
|
||||
@NonNull ApplicationInfo info,
|
||||
@Nullable IPlatformCompat platformCompat,
|
||||
int enabledAfter) {
|
||||
try {
|
||||
if (platformCompat != null) return platformCompat.isChangeEnabled(change, info);
|
||||
} catch (RemoteException ignore) {
|
||||
}
|
||||
return enabledAfter > 0 && info.targetSdkVersion > enabledAfter;
|
||||
}
|
||||
|
||||
// Returns the requested memory tagging level.
|
||||
private static int getRequestedMemtagLevel(
|
||||
@NonNull ApplicationInfo info,
|
||||
@Nullable ProcessInfo processInfo,
|
||||
@Nullable IPlatformCompat platformCompat) {
|
||||
// Look at the process attribute first.
|
||||
if (processInfo != null && processInfo.memtagMode != ApplicationInfo.MEMTAG_DEFAULT) {
|
||||
return memtagModeToZygoteMemtagLevel(processInfo.memtagMode);
|
||||
}
|
||||
|
||||
// Then at the application attribute.
|
||||
if (info.getMemtagMode() != ApplicationInfo.MEMTAG_DEFAULT) {
|
||||
return memtagModeToZygoteMemtagLevel(info.getMemtagMode());
|
||||
}
|
||||
|
||||
if (isCompatChangeEnabled(NATIVE_MEMTAG_SYNC, info, platformCompat, 0)) {
|
||||
return MEMORY_TAG_LEVEL_SYNC;
|
||||
}
|
||||
|
||||
if (isCompatChangeEnabled(NATIVE_MEMTAG_ASYNC, info, platformCompat, 0)) {
|
||||
return MEMORY_TAG_LEVEL_ASYNC;
|
||||
}
|
||||
|
||||
// Check to ensure the app hasn't explicitly opted-out of TBI via. the manifest attribute.
|
||||
if (!info.allowsNativeHeapPointerTagging()) {
|
||||
return MEMORY_TAG_LEVEL_NONE;
|
||||
}
|
||||
|
||||
String defaultLevel = SystemProperties.get("persist.arm64.memtag.app_default");
|
||||
if ("sync".equals(defaultLevel)) {
|
||||
return MEMORY_TAG_LEVEL_SYNC;
|
||||
} else if ("async".equals(defaultLevel)) {
|
||||
return MEMORY_TAG_LEVEL_ASYNC;
|
||||
}
|
||||
|
||||
// Check to see that the compat feature for TBI is enabled.
|
||||
if (isCompatChangeEnabled(
|
||||
NATIVE_HEAP_POINTER_TAGGING, info, platformCompat, Build.VERSION_CODES.Q)) {
|
||||
return MEMORY_TAG_LEVEL_TBI;
|
||||
}
|
||||
|
||||
return MEMORY_TAG_LEVEL_NONE;
|
||||
}
|
||||
|
||||
private static int decideTaggingLevel(
|
||||
@NonNull ApplicationInfo info,
|
||||
@Nullable ProcessInfo processInfo,
|
||||
@Nullable IPlatformCompat platformCompat) {
|
||||
// Get the desired tagging level (app manifest + compat features).
|
||||
int level = getRequestedMemtagLevel(info, processInfo, platformCompat);
|
||||
|
||||
// Take into account the hardware capabilities.
|
||||
if (nativeSupportsMemoryTagging()) {
|
||||
// MTE devices can not do TBI, because the Zygote process already has live MTE
|
||||
// allocations. Downgrade TBI to NONE.
|
||||
if (level == MEMORY_TAG_LEVEL_TBI) {
|
||||
level = MEMORY_TAG_LEVEL_NONE;
|
||||
}
|
||||
} else if (nativeSupportsTaggedPointers()) {
|
||||
// TBI-but-not-MTE devices downgrade MTE modes to TBI.
|
||||
// The idea is that if an app opts into full hardware tagging (MTE), it must be ok with
|
||||
// the "fake" pointer tagging (TBI).
|
||||
if (level == MEMORY_TAG_LEVEL_ASYNC || level == MEMORY_TAG_LEVEL_SYNC) {
|
||||
level = MEMORY_TAG_LEVEL_TBI;
|
||||
}
|
||||
} else {
|
||||
// Otherwise disable all tagging.
|
||||
level = MEMORY_TAG_LEVEL_NONE;
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
private static int decideGwpAsanLevel(
|
||||
@NonNull ApplicationInfo info,
|
||||
@Nullable ProcessInfo processInfo,
|
||||
@Nullable IPlatformCompat platformCompat) {
|
||||
// Look at the process attribute first.
|
||||
if (processInfo != null && processInfo.gwpAsanMode != ApplicationInfo.GWP_ASAN_DEFAULT) {
|
||||
return processInfo.gwpAsanMode == ApplicationInfo.GWP_ASAN_ALWAYS
|
||||
? GWP_ASAN_LEVEL_ALWAYS
|
||||
: GWP_ASAN_LEVEL_NEVER;
|
||||
}
|
||||
// Then at the application attribute.
|
||||
if (info.getGwpAsanMode() != ApplicationInfo.GWP_ASAN_DEFAULT) {
|
||||
return info.getGwpAsanMode() == ApplicationInfo.GWP_ASAN_ALWAYS
|
||||
? GWP_ASAN_LEVEL_ALWAYS
|
||||
: GWP_ASAN_LEVEL_NEVER;
|
||||
}
|
||||
// If the app does not specify gwpAsanMode, the default behavior is lottery among the
|
||||
// system apps, and disabled for user apps, unless overwritten by the compat feature.
|
||||
if (isCompatChangeEnabled(GWP_ASAN, info, platformCompat, 0)) {
|
||||
return GWP_ASAN_LEVEL_ALWAYS;
|
||||
}
|
||||
if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
|
||||
return GWP_ASAN_LEVEL_LOTTERY;
|
||||
}
|
||||
return GWP_ASAN_LEVEL_NEVER;
|
||||
}
|
||||
|
||||
private static boolean enableNativeHeapZeroInit(
|
||||
@NonNull ApplicationInfo info,
|
||||
@Nullable ProcessInfo processInfo,
|
||||
@Nullable IPlatformCompat platformCompat) {
|
||||
// Look at the process attribute first.
|
||||
if (processInfo != null
|
||||
&& processInfo.nativeHeapZeroInitialized != ApplicationInfo.ZEROINIT_DEFAULT) {
|
||||
return processInfo.nativeHeapZeroInitialized == ApplicationInfo.ZEROINIT_ENABLED;
|
||||
}
|
||||
// Then at the application attribute.
|
||||
if (info.getNativeHeapZeroInitialized() != ApplicationInfo.ZEROINIT_DEFAULT) {
|
||||
return info.getNativeHeapZeroInitialized() == ApplicationInfo.ZEROINIT_ENABLED;
|
||||
}
|
||||
// Compat feature last.
|
||||
if (isCompatChangeEnabled(NATIVE_HEAP_ZERO_INIT, info, platformCompat, 0)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Zygote runtimeFlags for memory safety features (MTE, GWP-ASan, nativeHeadZeroInit)
|
||||
* for a given app.
|
||||
*/
|
||||
public static int getMemorySafetyRuntimeFlags(
|
||||
@NonNull ApplicationInfo info,
|
||||
@Nullable ProcessInfo processInfo,
|
||||
@Nullable String instructionSet,
|
||||
@Nullable IPlatformCompat platformCompat) {
|
||||
int runtimeFlags = decideGwpAsanLevel(info, processInfo, platformCompat);
|
||||
// If instructionSet is non-null, this indicates that the system_server is spawning a
|
||||
// process with an ISA that may be different from its own. System (kernel and hardware)
|
||||
// compatibility for these features is checked in the decideTaggingLevel in the
|
||||
// system_server process (not the child process). As both MTE and TBI are only supported
|
||||
// in aarch64, we can simply ensure that the new process is also aarch64. This prevents
|
||||
// the mismatch where a 64-bit system server spawns a 32-bit child that thinks it should
|
||||
// enable some tagging variant. Theoretically, a 32-bit system server could exist that
|
||||
// spawns 64-bit processes, in which case the new process won't get any tagging. This is
|
||||
// fine as we haven't seen this configuration in practice, and we can reasonable assume
|
||||
// that if tagging is desired, the system server will be 64-bit.
|
||||
if (instructionSet == null || instructionSet.equals("arm64")) {
|
||||
runtimeFlags |= decideTaggingLevel(info, processInfo, platformCompat);
|
||||
}
|
||||
if (enableNativeHeapZeroInit(info, processInfo, platformCompat)) {
|
||||
runtimeFlags |= NATIVE_HEAP_ZERO_INIT_ENABLED;
|
||||
}
|
||||
return runtimeFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Zygote runtimeFlags for memory safety features (MTE, GWP-ASan, nativeHeadZeroInit)
|
||||
* for a secondary zygote (AppZygote or WebViewZygote).
|
||||
*/
|
||||
public static int getMemorySafetyRuntimeFlagsForSecondaryZygote(
|
||||
@NonNull ApplicationInfo info, @Nullable ProcessInfo processInfo) {
|
||||
final IPlatformCompat platformCompat =
|
||||
IPlatformCompat.Stub.asInterface(
|
||||
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
|
||||
int runtimeFlags =
|
||||
getMemorySafetyRuntimeFlags(
|
||||
info, processInfo, null /*instructionSet*/, platformCompat);
|
||||
|
||||
// TBI ("fake" pointer tagging) in AppZygote is controlled by a separate compat feature.
|
||||
if ((runtimeFlags & MEMORY_TAG_LEVEL_MASK) == MEMORY_TAG_LEVEL_TBI
|
||||
&& isCompatChangeEnabled(
|
||||
NATIVE_HEAP_POINTER_TAGGING_SECONDARY_ZYGOTE,
|
||||
info,
|
||||
platformCompat,
|
||||
Build.VERSION_CODES.S)) {
|
||||
// Reset memory tag level to NONE.
|
||||
runtimeFlags &= ~MEMORY_TAG_LEVEL_MASK;
|
||||
runtimeFlags |= MEMORY_TAG_LEVEL_NONE;
|
||||
}
|
||||
return runtimeFlags;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,7 +346,7 @@ enum RuntimeFlags : uint32_t {
|
||||
GWP_ASAN_LEVEL_NEVER = 0 << 21,
|
||||
GWP_ASAN_LEVEL_LOTTERY = 1 << 21,
|
||||
GWP_ASAN_LEVEL_ALWAYS = 2 << 21,
|
||||
NATIVE_HEAP_ZERO_INIT = 1 << 23,
|
||||
NATIVE_HEAP_ZERO_INIT_ENABLED = 1 << 23,
|
||||
PROFILEABLE = 1 << 24,
|
||||
};
|
||||
|
||||
@@ -1709,13 +1709,13 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
|
||||
// would be nice to have them for apps, we will have to wait until they are
|
||||
// proven out, have more efficient hardware, and/or apply them only to new
|
||||
// applications.
|
||||
if (!(runtime_flags & RuntimeFlags::NATIVE_HEAP_ZERO_INIT)) {
|
||||
if (!(runtime_flags & RuntimeFlags::NATIVE_HEAP_ZERO_INIT_ENABLED)) {
|
||||
mallopt(M_BIONIC_ZERO_INIT, 0);
|
||||
}
|
||||
|
||||
// Now that we've used the flag, clear it so that we don't pass unknown flags to the ART
|
||||
// runtime.
|
||||
runtime_flags &= ~RuntimeFlags::NATIVE_HEAP_ZERO_INIT;
|
||||
runtime_flags &= ~RuntimeFlags::NATIVE_HEAP_ZERO_INIT_ENABLED;
|
||||
|
||||
bool forceEnableGwpAsan = false;
|
||||
switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) {
|
||||
|
||||
@@ -4139,7 +4139,8 @@ public final class ActiveServices {
|
||||
|
||||
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
|
||||
final String procName = r.processName;
|
||||
HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
|
||||
HostingRecord hostingRecord = new HostingRecord("service", r.instanceName,
|
||||
r.definingPackageName, r.definingUid, r.serviceInfo.processName);
|
||||
ProcessRecord app;
|
||||
|
||||
if (!isolated) {
|
||||
@@ -4177,11 +4178,12 @@ public final class ActiveServices {
|
||||
app = r.isolationHostProc;
|
||||
if (WebViewZygote.isMultiprocessEnabled()
|
||||
&& r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
|
||||
hostingRecord = HostingRecord.byWebviewZygote(r.instanceName);
|
||||
hostingRecord = HostingRecord.byWebviewZygote(r.instanceName, r.definingPackageName,
|
||||
r.definingUid, r.serviceInfo.processName);
|
||||
}
|
||||
if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) {
|
||||
hostingRecord = HostingRecord.byAppZygote(r.instanceName, r.definingPackageName,
|
||||
r.definingUid);
|
||||
r.definingUid, r.serviceInfo.processName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,19 +56,27 @@ public final class HostingRecord {
|
||||
private final String mDefiningPackageName;
|
||||
private final int mDefiningUid;
|
||||
private final boolean mIsTopApp;
|
||||
private final String mDefiningProcessName;
|
||||
|
||||
public HostingRecord(String hostingType) {
|
||||
this(hostingType, null /* hostingName */, REGULAR_ZYGOTE, null /* definingPackageName */,
|
||||
-1 /* mDefiningUid */, false /* isTopApp */);
|
||||
-1 /* mDefiningUid */, false /* isTopApp */, null /* definingProcessName */);
|
||||
}
|
||||
|
||||
public HostingRecord(String hostingType, ComponentName hostingName) {
|
||||
this(hostingType, hostingName, REGULAR_ZYGOTE);
|
||||
}
|
||||
|
||||
public HostingRecord(String hostingType, ComponentName hostingName, String definingPackageName,
|
||||
int definingUid, String definingProcessName) {
|
||||
this(hostingType, hostingName.toShortString(), REGULAR_ZYGOTE, definingPackageName,
|
||||
definingUid, false /* isTopApp */, definingProcessName);
|
||||
}
|
||||
|
||||
public HostingRecord(String hostingType, ComponentName hostingName, boolean isTopApp) {
|
||||
this(hostingType, hostingName.toShortString(), REGULAR_ZYGOTE,
|
||||
null /* definingPackageName */, -1 /* mDefiningUid */, isTopApp /* isTopApp */);
|
||||
null /* definingPackageName */, -1 /* mDefiningUid */, isTopApp /* isTopApp */,
|
||||
null /* definingProcessName */);
|
||||
}
|
||||
|
||||
public HostingRecord(String hostingType, String hostingName) {
|
||||
@@ -81,17 +89,19 @@ public final class HostingRecord {
|
||||
|
||||
private HostingRecord(String hostingType, String hostingName, int hostingZygote) {
|
||||
this(hostingType, hostingName, hostingZygote, null /* definingPackageName */,
|
||||
-1 /* mDefiningUid */, false /* isTopApp */);
|
||||
-1 /* mDefiningUid */, false /* isTopApp */, null /* definingProcessName */);
|
||||
}
|
||||
|
||||
private HostingRecord(String hostingType, String hostingName, int hostingZygote,
|
||||
String definingPackageName, int definingUid, boolean isTopApp) {
|
||||
String definingPackageName, int definingUid, boolean isTopApp,
|
||||
String definingProcessName) {
|
||||
mHostingType = hostingType;
|
||||
mHostingName = hostingName;
|
||||
mHostingZygote = hostingZygote;
|
||||
mDefiningPackageName = definingPackageName;
|
||||
mDefiningUid = definingUid;
|
||||
mIsTopApp = isTopApp;
|
||||
mDefiningProcessName = definingProcessName;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
@@ -126,13 +136,25 @@ public final class HostingRecord {
|
||||
return mDefiningPackageName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the processName of the component we want to start as specified in the defining app's
|
||||
* manifest.
|
||||
*
|
||||
* @return the processName of the process in the hosting application
|
||||
*/
|
||||
public String getDefiningProcessName() {
|
||||
return mDefiningProcessName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a HostingRecord for a process that must spawn from the webview zygote
|
||||
* @param hostingName name of the component to be hosted in this process
|
||||
* @return The constructed HostingRecord
|
||||
*/
|
||||
public static HostingRecord byWebviewZygote(ComponentName hostingName) {
|
||||
return new HostingRecord("", hostingName.toShortString(), WEBVIEW_ZYGOTE);
|
||||
public static HostingRecord byWebviewZygote(ComponentName hostingName,
|
||||
String definingPackageName, int definingUid, String definingProcessName) {
|
||||
return new HostingRecord("", hostingName.toShortString(), WEBVIEW_ZYGOTE,
|
||||
definingPackageName, definingUid, false /* isTopApp */, definingProcessName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,9 +165,9 @@ public final class HostingRecord {
|
||||
* @return The constructed HostingRecord
|
||||
*/
|
||||
public static HostingRecord byAppZygote(ComponentName hostingName, String definingPackageName,
|
||||
int definingUid) {
|
||||
int definingUid, String definingProcessName) {
|
||||
return new HostingRecord("", hostingName.toShortString(), APP_ZYGOTE,
|
||||
definingPackageName, definingUid, false /* isTopApp */);
|
||||
definingPackageName, definingUid, false /* isTopApp */, definingProcessName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -70,7 +70,6 @@ import android.app.IApplicationThread;
|
||||
import android.app.IProcessObserver;
|
||||
import android.app.IUidObserver;
|
||||
import android.compat.annotation.ChangeId;
|
||||
import android.compat.annotation.Disabled;
|
||||
import android.compat.annotation.EnabledAfter;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
@@ -362,59 +361,6 @@ public final class ProcessList {
|
||||
// lmkd reconnect delay in msecs
|
||||
private static final long LMKD_RECONNECT_DELAY_MS = 1000;
|
||||
|
||||
/**
|
||||
* Native heap allocations will now have a non-zero tag in the most significant byte.
|
||||
* @see <a href="https://source.android.com/devices/tech/debug/tagged-pointers">Tagged
|
||||
* Pointers</a>
|
||||
*/
|
||||
@ChangeId
|
||||
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
|
||||
private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
|
||||
|
||||
/**
|
||||
* Native heap allocations in AppZygote process and its descendants will now have a
|
||||
* non-zero tag in the most significant byte.
|
||||
* @see <a href="https://source.android.com/devices/tech/debug/tagged-pointers">Tagged
|
||||
* Pointers</a>
|
||||
*/
|
||||
@ChangeId
|
||||
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S)
|
||||
private static final long NATIVE_HEAP_POINTER_TAGGING_APP_ZYGOTE = 207557677;
|
||||
|
||||
/**
|
||||
* Enable asynchronous (ASYNC) memory tag checking in this process. This
|
||||
* flag will only have an effect on hardware supporting the ARM Memory
|
||||
* Tagging Extension (MTE).
|
||||
*/
|
||||
@ChangeId
|
||||
@Disabled
|
||||
private static final long NATIVE_MEMTAG_ASYNC = 135772972; // This is a bug id.
|
||||
|
||||
/**
|
||||
* Enable synchronous (SYNC) memory tag checking in this process. This flag
|
||||
* will only have an effect on hardware supporting the ARM Memory Tagging
|
||||
* Extension (MTE). If both NATIVE_MEMTAG_ASYNC and this option is selected,
|
||||
* this option takes preference and MTE is enabled in SYNC mode.
|
||||
*/
|
||||
@ChangeId
|
||||
@Disabled
|
||||
private static final long NATIVE_MEMTAG_SYNC = 177438394; // This is a bug id.
|
||||
|
||||
/**
|
||||
* Enable automatic zero-initialization of native heap memory allocations.
|
||||
*/
|
||||
@ChangeId
|
||||
@Disabled
|
||||
private static final long NATIVE_HEAP_ZERO_INIT = 178038272; // This is a bug id.
|
||||
|
||||
/**
|
||||
* Enable sampled memory bug detection in the app.
|
||||
* @see <a href="https://source.android.com/devices/tech/debug/gwp-asan">GWP-ASan</a>.
|
||||
*/
|
||||
@ChangeId
|
||||
@Disabled
|
||||
private static final long GWP_ASAN = 135634846; // This is a bug id.
|
||||
|
||||
/**
|
||||
* Apps have no access to the private data directories of any other app, even if the other
|
||||
* app has made them world-readable.
|
||||
@@ -1681,136 +1627,6 @@ public final class ProcessList {
|
||||
return gidArray;
|
||||
}
|
||||
|
||||
private int memtagModeToZygoteMemtagLevel(int memtagMode) {
|
||||
switch (memtagMode) {
|
||||
case ApplicationInfo.MEMTAG_ASYNC:
|
||||
return Zygote.MEMORY_TAG_LEVEL_ASYNC;
|
||||
case ApplicationInfo.MEMTAG_SYNC:
|
||||
return Zygote.MEMORY_TAG_LEVEL_SYNC;
|
||||
default:
|
||||
return Zygote.MEMORY_TAG_LEVEL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the requested memory tagging level.
|
||||
private int getRequestedMemtagLevel(ProcessRecord app) {
|
||||
// Look at the process attribute first.
|
||||
if (app.processInfo != null
|
||||
&& app.processInfo.memtagMode != ApplicationInfo.MEMTAG_DEFAULT) {
|
||||
return memtagModeToZygoteMemtagLevel(app.processInfo.memtagMode);
|
||||
}
|
||||
|
||||
// Then at the application attribute.
|
||||
if (app.info.getMemtagMode() != ApplicationInfo.MEMTAG_DEFAULT) {
|
||||
return memtagModeToZygoteMemtagLevel(app.info.getMemtagMode());
|
||||
}
|
||||
|
||||
if (mPlatformCompat.isChangeEnabled(NATIVE_MEMTAG_SYNC, app.info)) {
|
||||
return Zygote.MEMORY_TAG_LEVEL_SYNC;
|
||||
}
|
||||
|
||||
if (mPlatformCompat.isChangeEnabled(NATIVE_MEMTAG_ASYNC, app.info)) {
|
||||
return Zygote.MEMORY_TAG_LEVEL_ASYNC;
|
||||
}
|
||||
|
||||
// Check to ensure the app hasn't explicitly opted-out of TBI via. the manifest attribute.
|
||||
if (!app.info.allowsNativeHeapPointerTagging()) {
|
||||
return Zygote.MEMORY_TAG_LEVEL_NONE;
|
||||
}
|
||||
|
||||
String defaultLevel = SystemProperties.get("persist.arm64.memtag.app_default");
|
||||
if ("sync".equals(defaultLevel)) {
|
||||
return Zygote.MEMORY_TAG_LEVEL_SYNC;
|
||||
} else if ("async".equals(defaultLevel)) {
|
||||
return Zygote.MEMORY_TAG_LEVEL_ASYNC;
|
||||
}
|
||||
|
||||
// Check to see that the compat feature for TBI is enabled.
|
||||
if (mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING, app.info)) {
|
||||
return Zygote.MEMORY_TAG_LEVEL_TBI;
|
||||
}
|
||||
|
||||
return Zygote.MEMORY_TAG_LEVEL_NONE;
|
||||
}
|
||||
|
||||
private int decideTaggingLevel(ProcessRecord app) {
|
||||
// Get the desired tagging level (app manifest + compat features).
|
||||
int level = getRequestedMemtagLevel(app);
|
||||
|
||||
// Take into account the hardware capabilities.
|
||||
if (Zygote.nativeSupportsMemoryTagging()) {
|
||||
// MTE devices can not do TBI, because the Zygote process already has live MTE
|
||||
// allocations. Downgrade TBI to NONE.
|
||||
if (level == Zygote.MEMORY_TAG_LEVEL_TBI) {
|
||||
level = Zygote.MEMORY_TAG_LEVEL_NONE;
|
||||
}
|
||||
} else if (Zygote.nativeSupportsTaggedPointers()) {
|
||||
// TBI-but-not-MTE devices downgrade MTE modes to TBI.
|
||||
// The idea is that if an app opts into full hardware tagging (MTE), it must be ok with
|
||||
// the "fake" pointer tagging (TBI).
|
||||
if (level == Zygote.MEMORY_TAG_LEVEL_ASYNC || level == Zygote.MEMORY_TAG_LEVEL_SYNC) {
|
||||
level = Zygote.MEMORY_TAG_LEVEL_TBI;
|
||||
}
|
||||
} else {
|
||||
// Otherwise disable all tagging.
|
||||
level = Zygote.MEMORY_TAG_LEVEL_NONE;
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
private int decideTaggingLevelForAppZygote(ProcessRecord app) {
|
||||
int level = decideTaggingLevel(app);
|
||||
// TBI ("fake" pointer tagging) in AppZygote is controlled by a separate compat feature.
|
||||
if (!mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING_APP_ZYGOTE, app.info)
|
||||
&& level == Zygote.MEMORY_TAG_LEVEL_TBI) {
|
||||
level = Zygote.MEMORY_TAG_LEVEL_NONE;
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
private int decideGwpAsanLevel(ProcessRecord app) {
|
||||
// Look at the process attribute first.
|
||||
if (app.processInfo != null
|
||||
&& app.processInfo.gwpAsanMode != ApplicationInfo.GWP_ASAN_DEFAULT) {
|
||||
return app.processInfo.gwpAsanMode == ApplicationInfo.GWP_ASAN_ALWAYS
|
||||
? Zygote.GWP_ASAN_LEVEL_ALWAYS
|
||||
: Zygote.GWP_ASAN_LEVEL_NEVER;
|
||||
}
|
||||
// Then at the application attribute.
|
||||
if (app.info.getGwpAsanMode() != ApplicationInfo.GWP_ASAN_DEFAULT) {
|
||||
return app.info.getGwpAsanMode() == ApplicationInfo.GWP_ASAN_ALWAYS
|
||||
? Zygote.GWP_ASAN_LEVEL_ALWAYS
|
||||
: Zygote.GWP_ASAN_LEVEL_NEVER;
|
||||
}
|
||||
// If the app does not specify gwpAsanMode, the default behavior is lottery among the
|
||||
// system apps, and disabled for user apps, unless overwritten by the compat feature.
|
||||
if (mPlatformCompat.isChangeEnabled(GWP_ASAN, app.info)) {
|
||||
return Zygote.GWP_ASAN_LEVEL_ALWAYS;
|
||||
}
|
||||
if ((app.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
|
||||
return Zygote.GWP_ASAN_LEVEL_LOTTERY;
|
||||
}
|
||||
return Zygote.GWP_ASAN_LEVEL_NEVER;
|
||||
}
|
||||
|
||||
private boolean enableNativeHeapZeroInit(ProcessRecord app) {
|
||||
// Look at the process attribute first.
|
||||
if (app.processInfo != null
|
||||
&& app.processInfo.nativeHeapZeroInitialized != ApplicationInfo.ZEROINIT_DEFAULT) {
|
||||
return app.processInfo.nativeHeapZeroInitialized == ApplicationInfo.ZEROINIT_ENABLED;
|
||||
}
|
||||
// Then at the application attribute.
|
||||
if (app.info.getNativeHeapZeroInitialized() != ApplicationInfo.ZEROINIT_DEFAULT) {
|
||||
return app.info.getNativeHeapZeroInitialized() == ApplicationInfo.ZEROINIT_ENABLED;
|
||||
}
|
||||
// Compat feature last.
|
||||
if (mPlatformCompat.isChangeEnabled(NATIVE_HEAP_ZERO_INIT, app.info)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if process start is successful, false otherwise.
|
||||
*/
|
||||
@@ -1992,8 +1808,6 @@ public final class ProcessList {
|
||||
runtimeFlags |= Zygote.USE_APP_IMAGE_STARTUP_CACHE;
|
||||
}
|
||||
|
||||
runtimeFlags |= decideGwpAsanLevel(app);
|
||||
|
||||
String invokeWith = null;
|
||||
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
|
||||
// Debuggable apps may include a wrapper script with their library directory.
|
||||
@@ -2024,23 +1838,21 @@ public final class ProcessList {
|
||||
app.setRequiredAbi(requiredAbi);
|
||||
app.setInstructionSet(instructionSet);
|
||||
|
||||
// If instructionSet is non-null, this indicates that the system_server is spawning a
|
||||
// process with an ISA that may be different from its own. System (kernel and hardware)
|
||||
// compatibility for these features is checked in the decideTaggingLevel in the
|
||||
// system_server process (not the child process). As both MTE and TBI are only supported
|
||||
// in aarch64, we can simply ensure that the new process is also aarch64. This prevents
|
||||
// the mismatch where a 64-bit system server spawns a 32-bit child that thinks it should
|
||||
// enable some tagging variant. Theoretically, a 32-bit system server could exist that
|
||||
// spawns 64-bit processes, in which case the new process won't get any tagging. This is
|
||||
// fine as we haven't seen this configuration in practice, and we can reasonable assume
|
||||
// that if tagging is desired, the system server will be 64-bit.
|
||||
if (instructionSet == null || instructionSet.equals("arm64")) {
|
||||
runtimeFlags |= decideTaggingLevel(app);
|
||||
// If this was an external service, the package name and uid in the passed in
|
||||
// ApplicationInfo have been changed to match those of the calling package;
|
||||
// that will incorrectly apply compat feature overrides for the calling package instead
|
||||
// of the defining one.
|
||||
ApplicationInfo definingAppInfo;
|
||||
if (hostingRecord.getDefiningPackageName() != null) {
|
||||
definingAppInfo = new ApplicationInfo(app.info);
|
||||
definingAppInfo.packageName = hostingRecord.getDefiningPackageName();
|
||||
definingAppInfo.uid = uid;
|
||||
} else {
|
||||
definingAppInfo = app.info;
|
||||
}
|
||||
|
||||
if (enableNativeHeapZeroInit(app)) {
|
||||
runtimeFlags |= Zygote.NATIVE_HEAP_ZERO_INIT;
|
||||
}
|
||||
runtimeFlags |= Zygote.getMemorySafetyRuntimeFlags(
|
||||
definingAppInfo, app.processInfo, instructionSet, mPlatformCompat);
|
||||
|
||||
// the per-user SELinux context must be set
|
||||
if (TextUtils.isEmpty(app.info.seInfoUser)) {
|
||||
@@ -2299,8 +2111,7 @@ public final class ProcessList {
|
||||
// not the calling one.
|
||||
appInfo.packageName = app.getHostingRecord().getDefiningPackageName();
|
||||
appInfo.uid = uid;
|
||||
int runtimeFlags = decideTaggingLevelForAppZygote(app);
|
||||
appZygote = new AppZygote(appInfo, uid, firstUid, lastUid, runtimeFlags);
|
||||
appZygote = new AppZygote(appInfo, app.processInfo, uid, firstUid, lastUid);
|
||||
mAppZygotes.put(app.info.processName, uid, appZygote);
|
||||
zygoteProcessList = new ArrayList<ProcessRecord>();
|
||||
mAppZygoteProcesses.put(appZygote, zygoteProcessList);
|
||||
@@ -3158,7 +2969,8 @@ public final class ProcessList {
|
||||
FrameworkStatsLog.write(FrameworkStatsLog.ISOLATED_UID_CHANGED, info.uid, uid,
|
||||
FrameworkStatsLog.ISOLATED_UID_CHANGED__EVENT__CREATED);
|
||||
}
|
||||
final ProcessRecord r = new ProcessRecord(mService, info, proc, uid);
|
||||
final ProcessRecord r = new ProcessRecord(mService, info, proc, uid,
|
||||
hostingRecord.getDefiningUid(), hostingRecord.getDefiningProcessName());
|
||||
final ProcessStateRecord state = r.mState;
|
||||
|
||||
if (!mService.mBooted && !mService.mBooting
|
||||
|
||||
@@ -492,24 +492,33 @@ class ProcessRecord implements WindowProcessListener {
|
||||
|
||||
ProcessRecord(ActivityManagerService _service, ApplicationInfo _info, String _processName,
|
||||
int _uid) {
|
||||
this(_service, _info, _processName, _uid, -1, null);
|
||||
}
|
||||
|
||||
ProcessRecord(ActivityManagerService _service, ApplicationInfo _info, String _processName,
|
||||
int _uid, int _definingUid, String _definingProcessName) {
|
||||
mService = _service;
|
||||
mProcLock = _service.mProcLock;
|
||||
info = _info;
|
||||
ProcessInfo procInfo = null;
|
||||
if (_service.mPackageManagerInt != null) {
|
||||
ArrayMap<String, ProcessInfo> processes =
|
||||
_service.mPackageManagerInt.getProcessesForUid(_uid);
|
||||
if (processes != null) {
|
||||
procInfo = processes.get(_processName);
|
||||
if (procInfo != null && procInfo.deniedPermissions == null
|
||||
&& procInfo.gwpAsanMode == ApplicationInfo.GWP_ASAN_DEFAULT
|
||||
&& procInfo.memtagMode == ApplicationInfo.MEMTAG_DEFAULT
|
||||
&& procInfo.nativeHeapZeroInitialized == ApplicationInfo.ZEROINIT_DEFAULT) {
|
||||
// If this process hasn't asked for permissions to be denied, or for a
|
||||
// non-default GwpAsan mode, or any other non-default setting, then we don't
|
||||
// care about it.
|
||||
procInfo = null;
|
||||
}
|
||||
if (_definingUid > 0) {
|
||||
ArrayMap<String, ProcessInfo> processes =
|
||||
_service.mPackageManagerInt.getProcessesForUid(_definingUid);
|
||||
if (processes != null) procInfo = processes.get(_definingProcessName);
|
||||
} else {
|
||||
ArrayMap<String, ProcessInfo> processes =
|
||||
_service.mPackageManagerInt.getProcessesForUid(_uid);
|
||||
if (processes != null) procInfo = processes.get(_processName);
|
||||
}
|
||||
if (procInfo != null && procInfo.deniedPermissions == null
|
||||
&& procInfo.gwpAsanMode == ApplicationInfo.GWP_ASAN_DEFAULT
|
||||
&& procInfo.memtagMode == ApplicationInfo.MEMTAG_DEFAULT
|
||||
&& procInfo.nativeHeapZeroInitialized == ApplicationInfo.ZEROINIT_DEFAULT) {
|
||||
// If this process hasn't asked for permissions to be denied, or for a
|
||||
// non-default GwpAsan mode, or any other non-default setting, then we don't
|
||||
// care about it.
|
||||
procInfo = null;
|
||||
}
|
||||
}
|
||||
processInfo = procInfo;
|
||||
|
||||
@@ -1000,7 +1000,7 @@ public class ApplicationExitInfoTest {
|
||||
final String dummyPackageName = "com.android.test";
|
||||
final String dummyClassName = ".Foo";
|
||||
app.setHostingRecord(HostingRecord.byAppZygote(new ComponentName(
|
||||
dummyPackageName, dummyClassName), "", definingUid));
|
||||
dummyPackageName, dummyClassName), "", definingUid, ""));
|
||||
}
|
||||
app.mServices.setConnectionGroup(connectionGroup);
|
||||
app.mState.setReportedProcState(procState);
|
||||
|
||||
Reference in New Issue
Block a user