summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java95
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java98
2 files changed, 189 insertions, 4 deletions
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index c393213c5e85..fbe7e704a653 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -107,6 +107,7 @@ import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.os.storage.StorageManagerInternal;
+import android.provider.DeviceConfig;
import android.system.Os;
import android.system.OsConstants;
import android.text.TextUtils;
@@ -181,6 +182,8 @@ public final class ProcessList {
static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
"persist.sys.vold_app_data_isolation_enabled";
+ private static final String APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS = ":isSdkSandboxNext";
+
// OOM adjustments for processes in various states:
// Uninitialized value for any major or minor adj fields
@@ -538,6 +541,78 @@ public final class ProcessList {
ActivityManagerGlobalLock mProcLock;
+ private static final String PROPERTY_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS =
+ "apply_sdk_sandbox_next_restrictions";
+ private static final boolean DEFAULT_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS = false;
+
+ @GuardedBy("mService")
+ private ProcessListSettingsListener mProcessListSettingsListener;
+
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ ProcessListSettingsListener getProcessListSettingsListener() {
+ synchronized (mService) {
+ if (mProcessListSettingsListener == null) {
+ mProcessListSettingsListener = new ProcessListSettingsListener(mService.mContext);
+ mProcessListSettingsListener.registerObserver();
+ }
+ return mProcessListSettingsListener;
+ }
+ }
+
+ static class ProcessListSettingsListener implements DeviceConfig.OnPropertiesChangedListener {
+
+ private final Context mContext;
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private boolean mSdkSandboxApplyRestrictionsNext =
+ DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ADSERVICES,
+ PROPERTY_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS,
+ DEFAULT_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS);
+
+ ProcessListSettingsListener(Context context) {
+ mContext = context;
+ }
+
+ private void registerObserver() {
+ DeviceConfig.addOnPropertiesChangedListener(
+ DeviceConfig.NAMESPACE_ADSERVICES, mContext.getMainExecutor(), this);
+ }
+
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ void unregisterObserver() {
+ DeviceConfig.removeOnPropertiesChangedListener(this);
+ }
+
+ boolean applySdkSandboxRestrictionsNext() {
+ synchronized (mLock) {
+ return mSdkSandboxApplyRestrictionsNext;
+ }
+ }
+
+ @Override
+ public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
+ synchronized (mLock) {
+ for (String name : properties.getKeyset()) {
+ if (name == null) {
+ continue;
+ }
+
+ switch (name) {
+ case PROPERTY_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS:
+ mSdkSandboxApplyRestrictionsNext =
+ properties.getBoolean(
+ PROPERTY_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS,
+ DEFAULT_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS);
+ break;
+ default:
+ }
+ }
+ }
+ }
+ }
+
final class IsolatedUidRange {
@VisibleForTesting
public final int mFirstUid;
@@ -1883,8 +1958,9 @@ public final class ProcessList {
new IllegalStateException("SELinux tag not defined for "
+ app.info.packageName + " (uid " + app.uid + ")"));
}
- final String seInfo = app.info.seInfo
- + (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser);
+
+ String seInfo = updateSeInfo(app);
+
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
final String entryPoint = "android.app.ActivityThread";
@@ -1907,6 +1983,21 @@ public final class ProcessList {
}
}
+ @VisibleForTesting
+ @GuardedBy("mService")
+ String updateSeInfo(ProcessRecord app) {
+ String extraInfo = "";
+ // By the time the first the SDK sandbox process is started, device config service
+ // should be available.
+ if (app.isSdkSandbox
+ && getProcessListSettingsListener().applySdkSandboxRestrictionsNext()) {
+ extraInfo = APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS;
+ }
+
+ return app.info.seInfo
+ + (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser) + extraInfo;
+ }
+
@GuardedBy("mService")
boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app,
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index f82d246d68bd..467c439bae01 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -37,6 +37,7 @@ import static com.android.server.am.ProcessList.NETWORK_STATE_BLOCK;
import static com.android.server.am.ProcessList.NETWORK_STATE_NO_CHANGE;
import static com.android.server.am.ProcessList.NETWORK_STATE_UNBLOCK;
+import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertEquals;
@@ -60,6 +61,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import android.Manifest;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
@@ -82,13 +84,16 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.server.LocalServices;
import com.android.server.am.ActivityManagerService.StickyBroadcast;
import com.android.server.am.ProcessList.IsolatedUidRange;
@@ -106,6 +111,7 @@ import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
import java.io.File;
import java.util.ArrayList;
@@ -137,7 +143,9 @@ public class ActivityManagerServiceTest {
private static final String TEST_EXTRA_KEY1 = "com.android.server.am.TEST_EXTRA_KEY1";
private static final String TEST_EXTRA_VALUE1 = "com.android.server.am.TEST_EXTRA_VALUE1";
-
+ private static final String PROPERTY_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS =
+ "apply_sdk_sandbox_next_restrictions";
+ private static final String APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS = ":isSdkSandboxNext";
private static final int TEST_UID = 11111;
private static final int USER_ID = 666;
@@ -154,6 +162,7 @@ public class ActivityManagerServiceTest {
};
private static PackageManagerInternal sPackageManagerInternal;
+ private static ProcessList.ProcessListSettingsListener sProcessListSettingsListener;
@BeforeClass
public static void setUpOnce() {
@@ -181,7 +190,6 @@ public class ActivityManagerServiceTest {
private ActivityManagerService mAms;
private HandlerThread mHandlerThread;
private TestHandler mHandler;
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -203,6 +211,15 @@ public class ActivityManagerServiceTest {
mAms.mActivityTaskManager.initialize(null, null, mHandler.getLooper());
mHandler.setRunnablesToIgnore(
List.of(mAms.mUidObserverController.getDispatchRunnableForTest()));
+
+ // Required for updating DeviceConfig.
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .adoptShellPermissionIdentity(
+ Manifest.permission.READ_DEVICE_CONFIG,
+ Manifest.permission.WRITE_DEVICE_CONFIG);
+ sProcessListSettingsListener = mAms.mProcessList.getProcessListSettingsListener();
+ assertThat(sProcessListSettingsListener).isNotNull();
}
private void mockNoteOperation() {
@@ -216,6 +233,12 @@ public class ActivityManagerServiceTest {
@After
public void tearDown() {
mHandlerThread.quit();
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ if (sProcessListSettingsListener != null) {
+ sProcessListSettingsListener.unregisterObserver();
+ }
}
@SuppressWarnings("GuardedBy")
@@ -268,6 +291,77 @@ public class ActivityManagerServiceTest {
false); // expectNotify
}
+ @SuppressWarnings("GuardedBy")
+ @SmallTest
+ @Test
+ public void defaultSdkSandboxNextRestrictions() throws Exception {
+ sProcessListSettingsListener.onPropertiesChanged(
+ new DeviceConfig.Properties(
+ DeviceConfig.NAMESPACE_ADSERVICES,
+ Map.of(PROPERTY_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS, "")));
+ assertThat(
+ sProcessListSettingsListener.applySdkSandboxRestrictionsNext())
+ .isFalse();
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @SmallTest
+ @Test
+ public void doNotApplySdkSandboxNextRestrictions() throws Exception {
+ MockitoSession mockitoSession =
+ ExtendedMockito.mockitoSession().spyStatic(Process.class).startMocking();
+ try {
+ sProcessListSettingsListener.onPropertiesChanged(
+ new DeviceConfig.Properties(
+ DeviceConfig.NAMESPACE_ADSERVICES,
+ Map.of(PROPERTY_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS, "false")));
+ assertThat(
+ sProcessListSettingsListener.applySdkSandboxRestrictionsNext())
+ .isFalse();
+ ExtendedMockito.doReturn(true).when(() -> Process.isSdkSandboxUid(anyInt()));
+ ApplicationInfo info = new ApplicationInfo();
+ info.packageName = "com.android.sdksandbox";
+ info.seInfo = "default:targetSdkVersion=34:complete";
+ final ProcessRecord appRec = new ProcessRecord(
+ mAms, info, TAG, Process.FIRST_SDK_SANDBOX_UID,
+ /* sdkSandboxClientPackageName= */ "com.example.client",
+ /* definingUid= */ 0, /* definingProcessName= */ "");
+ assertThat(mAms.mProcessList.updateSeInfo(appRec)).doesNotContain(
+ APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS);
+ } finally {
+ mockitoSession.finishMocking();
+ }
+ }
+ @SuppressWarnings("GuardedBy")
+ @SmallTest
+ @Test
+ public void applySdkSandboxNextRestrictions() throws Exception {
+ MockitoSession mockitoSession =
+ ExtendedMockito.mockitoSession().spyStatic(Process.class).startMocking();
+ try {
+ sProcessListSettingsListener.onPropertiesChanged(
+ new DeviceConfig.Properties(
+ DeviceConfig.NAMESPACE_ADSERVICES,
+ Map.of(PROPERTY_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS, "true")));
+ assertThat(
+ sProcessListSettingsListener.applySdkSandboxRestrictionsNext())
+ .isTrue();
+ ExtendedMockito.doReturn(true).when(() -> Process.isSdkSandboxUid(anyInt()));
+ ApplicationInfo info = new ApplicationInfo();
+ info.packageName = "com.android.sdksandbox";
+ info.seInfo = "default:targetSdkVersion=34:complete";
+ final ProcessRecord appRec = new ProcessRecord(
+ mAms, info, TAG, Process.FIRST_SDK_SANDBOX_UID,
+ /* sdkSandboxClientPackageName= */ "com.example.client",
+ /* definingUid= */ 0, /* definingProcessName= */ "");
+ assertThat(mAms.mProcessList.updateSeInfo(appRec)).contains(
+ APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS);
+ } finally {
+ mockitoSession.finishMocking();
+ }
+ }
+
+
private UidRecord addUidRecord(int uid) {
final UidRecord uidRec = new UidRecord(uid, mAms);
uidRec.procStateSeqWaitingForNetwork = 1;