diff options
| -rw-r--r-- | services/core/java/com/android/server/am/ProcessList.java | 95 | ||||
| -rw-r--r-- | services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java | 98 |
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; |