Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions core/api/module-lib-current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ package android.content {

public class Intent implements Cloneable android.os.Parcelable {
field public static final String ACTION_SETTING_RESTORED = "android.os.action.SETTING_RESTORED";
field public static final String ACTION_USER_STARTED = "android.intent.action.USER_STARTED";
field public static final String ACTION_USER_STOPPED = "android.intent.action.USER_STOPPED";
field public static final String EXTRA_SETTING_NAME = "setting_name";
field public static final String EXTRA_SETTING_NEW_VALUE = "new_value";
field public static final String EXTRA_SETTING_PREVIOUS_VALUE = "previous_value";
Expand All @@ -146,6 +148,7 @@ package android.content.pm {
}

public abstract class PackageManager {
method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public abstract android.content.pm.PackageInfo getPackageInfoAsUser(@NonNull String, int, int) throws android.content.pm.PackageManager.NameNotFoundException;
method @NonNull public String getSdkSandboxPackageName();
method @RequiresPermission(android.Manifest.permission.MAKE_UID_VISIBLE) public void makeUidVisible(int, int);
field public static final String EXTRA_VERIFICATION_ROOT_HASH = "android.content.pm.extra.VERIFICATION_ROOT_HASH";
Expand All @@ -157,6 +160,7 @@ package android.content.pm {
package android.ext {

public class ConnectivityUtil {
method public static boolean isAppStrictLeakBlockingEnabled(@NonNull android.content.Context, int, @NonNull android.content.pm.ApplicationInfo, @NonNull android.content.pm.GosPackageState);
method public static boolean isRegularAppWithLockdownVpnEnabled(@NonNull android.content.Context, int);
method public static boolean isSystem(@NonNull android.content.Context, int);
}
Expand Down Expand Up @@ -629,6 +633,7 @@ package android.os {
public final class UserHandle implements android.os.Parcelable {
method public static int getUid(int, int);
method public static int getUserId(int);
method public static boolean isCore(int);
}

public class UserManager {
Expand Down
11 changes: 11 additions & 0 deletions core/api/system-current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5867,6 +5867,17 @@ package android.ext {
field public static final int UNKNOWN = 0; // 0x0
}

public class SettingsIntents {
method @NonNull public static android.content.Intent createAppIntent(@NonNull android.content.Context, @NonNull String, @NonNull String, boolean);
field public static final String APP_HARDENED_MALLOC = "android.settings.OPEN_APP_HARDENED_MALLOC_SETTINGS";
field public static final String APP_MANAGE_PLAY_INTEGRITY_API = "android.settings.OPEN_APP_MANAGE_PLAY_INTEGRITY_API_SETTINGS";
field public static final String APP_MEMORY_DYN_CODE_LOADING = "android.settings.OPEN_APP_MEMORY_DYN_CODE_LOADING_SETTINGS";
field public static final String APP_MEMTAG = "android.settings.OPEN_APP_MEMTAG_SETTINGS";
field public static final String APP_NATIVE_DEBUGGING = "android.settings.OPEN_APP_NATIVE_DEBUGGING_SETTINGS";
field public static final String APP_STORAGE_DYN_CODE_LOADING = "android.settings.OPEN_APP_STORAGE_DYN_CODE_LOADING_SETTINGS";
field public static final String APP_STRICT_LEAK_BLOCKING = "android.settings.OPEN_APP_STRICT_LEAK_BLOCKING";
}

}

package android.ext.cscopes {
Expand Down
2 changes: 2 additions & 0 deletions core/java/android/content/Intent.java
Original file line number Diff line number Diff line change
Expand Up @@ -4237,6 +4237,7 @@ public static Intent createChooser(Intent target, CharSequence title, IntentSend
* the current state of the user.
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final String ACTION_USER_STARTED =
"android.intent.action.USER_STARTED";

Expand Down Expand Up @@ -4302,6 +4303,7 @@ public static Intent createChooser(Intent target, CharSequence title, IntentSend
* @hide
*/
@TestApi
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final String ACTION_USER_STOPPED =
"android.intent.action.USER_STOPPED";

Expand Down
13 changes: 11 additions & 2 deletions core/java/android/content/pm/GosPackageState.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import android.util.Log;
import android.util.SparseArray;

import com.android.internal.annotations.VisibleForTesting;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Objects;
Expand Down Expand Up @@ -402,11 +404,18 @@ public Editor setNotifyUidAfterApply(boolean v) {
public boolean apply() {
try {
return ActivityThread.getPackageManager().setGosPackageState(packageName, userId,
new GosPackageState(flagStorage1, packageFlagStorage, storageScopes, contactScopes),
editorFlags);
toState(), editorFlags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

/** @hide */
@VisibleForTesting
@NonNull
public GosPackageState toState() {
return new GosPackageState(flagStorage1, packageFlagStorage, storageScopes,
contactScopes);
}
}
}
13 changes: 12 additions & 1 deletion core/java/android/content/pm/GosPackageStateFlag.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/** @hide */
/**
* GosPackageStateFlag defines the valid flags for GosPackageState. When adding a new flag, its
* permissions must also be set in GosPackageStatePermissions.
*
* @hide
*/
@SystemApi
public interface GosPackageStateFlag {
/* SysApi */ int STORAGE_SCOPES_ENABLED = 0;
Expand Down Expand Up @@ -38,6 +43,9 @@ public interface GosPackageStateFlag {
/** @hide */ int BLOCK_PLAY_INTEGRITY_API = 28;
/** @hide */ int USE_EXEC_SPAWNING_NON_DEFAULT = 29;
/** @hide */ int USE_EXEC_SPAWNING = 30;
/** @hide */ int STRICT_LEAK_BLOCKING_NON_DEFAULT = 31;
/** @hide */ int STRICT_LEAK_BLOCKING = 32;
/** @hide */ int STRICT_LEAK_BLOCKING_SUPPRESS_NOTIF = 33;

/** @hide */
@IntDef(value = {
Expand Down Expand Up @@ -68,6 +76,9 @@ public interface GosPackageStateFlag {
BLOCK_PLAY_INTEGRITY_API,
USE_EXEC_SPAWNING_NON_DEFAULT,
USE_EXEC_SPAWNING,
STRICT_LEAK_BLOCKING_NON_DEFAULT,
STRICT_LEAK_BLOCKING,
STRICT_LEAK_BLOCKING_SUPPRESS_NOTIF,
})
@Retention(RetentionPolicy.SOURCE)
@interface Enum {}
Expand Down
2 changes: 2 additions & 0 deletions core/java/android/content/pm/PackageManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -6157,6 +6157,8 @@ public PackageInfo getPackageInfo(@NonNull VersionedPackage versionedPackage,
@SuppressWarnings("HiddenAbstractMethod")
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
@UnsupportedAppUsage
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@NonNull
public abstract PackageInfo getPackageInfoAsUser(@NonNull String packageName,
int flags, @UserIdInt int userId) throws NameNotFoundException;

Expand Down
7 changes: 7 additions & 0 deletions core/java/android/ext/ConnectivityUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import android.annotation.SystemApi;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.GosPackageState;
import android.content.pm.PackageManager;
import android.ext.settings.app.AswStrictLeakBlocking;
import android.os.UserHandle;
import android.provider.Settings;

Expand Down Expand Up @@ -43,4 +45,9 @@ public static boolean isRegularAppWithLockdownVpnEnabled(@NonNull Context contex
Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0, UserHandle.getUserId(uid));
return lockdownVpnEnabled == 1 && !isSystem(context, uid);
}

public static boolean isAppStrictLeakBlockingEnabled(@NonNull Context context, int uid,
@NonNull ApplicationInfo ai, @NonNull GosPackageState ps) {
return AswStrictLeakBlocking.I.get(context, uid, ai, ps);
}
}
14 changes: 12 additions & 2 deletions core/java/android/ext/SettingsIntents.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package android.ext;

import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;

/** @hide */
@SystemApi
public class SettingsIntents {

public static final String APP_NATIVE_DEBUGGING = "android.settings.OPEN_APP_NATIVE_DEBUGGING_SETTINGS";
Expand All @@ -13,12 +16,19 @@ public class SettingsIntents {
public static final String APP_MEMORY_DYN_CODE_LOADING = "android.settings.OPEN_APP_MEMORY_DYN_CODE_LOADING_SETTINGS";
public static final String APP_STORAGE_DYN_CODE_LOADING = "android.settings.OPEN_APP_STORAGE_DYN_CODE_LOADING_SETTINGS";
public static final String APP_MANAGE_PLAY_INTEGRITY_API = "android.settings.OPEN_APP_MANAGE_PLAY_INTEGRITY_API_SETTINGS";
public static final String APP_STRICT_LEAK_BLOCKING = "android.settings.OPEN_APP_STRICT_LEAK_BLOCKING";

public static Intent getAppIntent(Context ctx, String action, String pkgName) {
// This constructor keeps the linter happy.
private SettingsIntents() {}

public static @NonNull Intent createAppIntent(@NonNull Context ctx, @NonNull String action,
@NonNull String pkgName, boolean newTask) {
var i = new Intent(action);
i.setData(Uri.fromParts("package", pkgName, null));
i.setPackage(KnownSystemPackages.get(ctx).settings);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
if (newTask) {
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
}
return i;
}
}
41 changes: 41 additions & 0 deletions core/java/android/ext/settings/app/AswStrictLeakBlocking.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package android.ext.settings.app;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.GosPackageState;
import android.content.pm.GosPackageStateFlag;

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

private AswStrictLeakBlocking() {
gosPsFlag = GosPackageStateFlag.STRICT_LEAK_BLOCKING;
gosPsFlagNonDefault = GosPackageStateFlag.STRICT_LEAK_BLOCKING_NON_DEFAULT;
gosPsFlagSuppressNotif = GosPackageStateFlag.STRICT_LEAK_BLOCKING_SUPPRESS_NOTIF;
}

@Override
public Boolean getImmutableValue(Context ctx, int userId, ApplicationInfo appInfo,
GosPackageState ps, StateInfo si) {
if (appInfo.isSystemApp()) {
si.immutabilityReason = IR_IS_SYSTEM_APP;
// This is overly permissive because not all system apps have permissions that allow
// them to bypass lockdown VPNs (netd PERMISSION_SYSTEM). With that said, it's plausible
// that a system app without PERMISSION_SYSTEM could have a valid reason to use
// functionality gated behind strict leak blocking. GrapheneOS ships proprietary core
// components and system apps that could fall under that category.
// TODO: Determine which core components and system apps actually need this to be false
// (this will be difficult to maintain).
return false;
}

return null;
}

@Override
protected boolean getDefaultValueInner(Context ctx, int userId, ApplicationInfo appInfo,
GosPackageState ps, StateInfo si) {
return true;
}
}
1 change: 1 addition & 0 deletions core/java/android/os/UserHandle.java
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ public static boolean isApp(int uid) {
* Whether a UID belongs to a system core component or not.
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static boolean isCore(int uid) {
if (uid >= 0) {
final int appId = getAppId(uid);
Expand Down
3 changes: 3 additions & 0 deletions core/res/res/values/string_ext.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
<string name="notif_native_debug_title">%1$s tried to use native code debugging</string>
<java-symbol type="string" name="notif_native_debug_title" />

<string name="notif_app_strict_leak_blocking_title">%1$s tried to bypass strict leak blocking</string>
<java-symbol type="string" name="notif_app_strict_leak_blocking_title" />

<string name="notif_ch_system_journal">System journal</string>
<java-symbol type="string" name="notif_ch_system_journal" />

Expand Down
1 change: 1 addition & 0 deletions services/api/current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ package com.android.server.am {
method public boolean canStartForegroundService(int, int, @NonNull String);
method @FlaggedApi("com.android.server.am.get_package_names_for_pid_api") @NonNull public String[] getPackageNamesForPid(int, int);
method public void killSdkSandboxClientAppProcess(@NonNull android.os.IBinder);
method public void showAppStrictLeakBlockingNotification(int, int);
method @FlaggedApi("com.android.server.am.fgs_delegate_system_api") public boolean startForegroundServiceDelegate(@NonNull com.android.server.am.ForegroundServiceDelegationParams, @Nullable android.content.ServiceConnection);
method @Nullable public android.content.ComponentName startSdkSandboxService(@NonNull android.content.Intent, int, @NonNull String, @NonNull String) throws android.os.RemoteException;
method @FlaggedApi("com.android.server.am.fgs_delegate_system_api") public void stopForegroundServiceDelegate(@NonNull com.android.server.am.ForegroundServiceDelegationParams);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,4 +224,6 @@ boolean startForegroundServiceDelegate(
@FlaggedApi(Flags.FLAG_FGS_DELEGATE_SYSTEM_API)
void stopForegroundServiceDelegate(
@NonNull ForegroundServiceDelegationParams params);

void showAppStrictLeakBlockingNotification(int uid, int pid);
}
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@
import com.android.server.contentcapture.ContentCaptureManagerInternal;
import com.android.server.crashrecovery.CrashRecoveryHelper;
import com.android.server.criticalevents.CriticalEventLog;
import com.android.server.ext.AppStrictLeakBlockingUtil;
import com.android.server.ext.DynCodeLoadingUtils;
import com.android.server.ext.PackageManagerHooks;
import com.android.server.firewall.IntentFirewall;
Expand Down Expand Up @@ -19410,6 +19411,11 @@ public void dispatchGosPackageStateCallbacks(int uid) {
public ProcessRecordSnapshot getProcessRecordByPid(int pid) {
return mProcessList.getProcessRecordByPid(pid);
}

@Override
public void showAppStrictLeakBlockingNotification(int uid, int pid) {
AppStrictLeakBlockingUtil.showNotification(mContext, uid, pid);
}
}

long inputDispatchingTimedOut(int pid, final boolean aboveSystem, TimeoutRecord timeoutRecord) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.android.server.ext;

import android.app.ActivityManagerInternal;
import android.content.Context;
import android.content.pm.GosPackageStateFlag;
import android.content.pm.PackageManagerInternal;
import android.ext.SettingsIntents;
import android.util.Slog;

import com.android.internal.R;
import com.android.server.LocalServices;
import com.android.server.pm.Computer;

public class AppStrictLeakBlockingUtil {
private static final String TAG = AppStrictLeakBlockingUtil.class.getSimpleName();

public static void showNotification(Context ctx, int uid, int pid) {
String firstPackageName = null;

var ami = LocalServices.getService(ActivityManagerInternal.class);
ActivityManagerInternal.ProcessRecordSnapshot prs = ami.getProcessRecordByPid(pid);
if (prs != null && prs.appInfo != null) {
firstPackageName = prs.appInfo.packageName;
} else {
var pmi = LocalServices.getService(PackageManagerInternal.class);
Computer snapshot = (Computer)pmi.snapshot();
String[] packages = snapshot.getPackagesForUid(uid);
if (packages != null && packages.length == 1) {
firstPackageName = packages[0];
}
}

if (firstPackageName == null) {
Slog.d(TAG, "firstPackageName is null for uid " + uid);
return;
}

var n = AppSwitchNotification.maybeCreate(ctx, firstPackageName, uid,
SettingsIntents.APP_STRICT_LEAK_BLOCKING);
if (n == null) {
return;
}

n.titleRes = R.string.notif_app_strict_leak_blocking_title;
n.gosPsFlagSuppressNotif = GosPackageStateFlag.STRICT_LEAK_BLOCKING_SUPPRESS_NOTIF;
n.maybeShow();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public void maybeShow() {
nb.setContentTitle(ctx.getString(titleRes, appLabel));
}
{
var intent = SettingsIntents.getAppIntent(ctx, settingsIntentAction, pkgName);
var intent = SettingsIntents.createAppIntent(ctx, settingsIntentAction, pkgName, true);
var pi = PendingIntent.getActivityAsUser(ctx, 0, intent,
PendingIntent.FLAG_IMMUTABLE, null, userHandle);
nb.setContentIntent(pi);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
import java.util.Objects;

import static android.content.pm.GosPackageStateFlag.ALLOW_ACCESS_TO_OBB_DIRECTORY;
import static android.content.pm.GosPackageStateFlag.STRICT_LEAK_BLOCKING;
import static android.content.pm.GosPackageStateFlag.STRICT_LEAK_BLOCKING_NON_DEFAULT;
import static android.content.pm.GosPackageStateFlag.STRICT_LEAK_BLOCKING_SUPPRESS_NOTIF;
import static android.content.pm.GosPackageStateFlag.BLOCK_NATIVE_DEBUGGING;
import static android.content.pm.GosPackageStateFlag.BLOCK_NATIVE_DEBUGGING_NON_DEFAULT;
import static android.content.pm.GosPackageStateFlag.BLOCK_NATIVE_DEBUGGING_SUPPRESS_NOTIF;
Expand Down Expand Up @@ -145,6 +148,9 @@ static void init(PackageManagerService pm) {
USE_EXEC_SPAWNING_NON_DEFAULT,
USE_EXEC_SPAWNING,
ENABLE_EXPLOIT_PROTECTION_COMPAT_MODE,
STRICT_LEAK_BLOCKING_NON_DEFAULT,
STRICT_LEAK_BLOCKING,
STRICT_LEAK_BLOCKING_SUPPRESS_NOTIF,
};
builder()
.readWriteFlags(settingsReadWriteFlags)
Expand Down