Introducing the new DeviceConfig flag to gate dex verification for the SDKRT
Bug: b/231441674
Test: SdkSandboxSettingsListenerUnitTest && SdkSandboxVerifierReceiverUnitTest
Flag: EXEMPT b/337358613
PS_FLAG: SdkInstallChecks__verify_dex_files
Change-Id: I465a3a1b47f63535c43fa9405f8ec30e1faa908b
diff --git a/sdksandbox/service/java/com/android/server/sdksandbox/SdkSandboxManagerService.java b/sdksandbox/service/java/com/android/server/sdksandbox/SdkSandboxManagerService.java
index 3e1bc21..6c4d40b 100644
--- a/sdksandbox/service/java/com/android/server/sdksandbox/SdkSandboxManagerService.java
+++ b/sdksandbox/service/java/com/android/server/sdksandbox/SdkSandboxManagerService.java
@@ -391,6 +391,7 @@
mSdkSandboxStorageManager = mInjector.getSdkSandboxStorageManager();
mSdkSandboxStatsdLogger = mInjector.getSdkSandboxStatsdLogger();
mSdkSandboxRestrictionManager = mInjector.getSdkSandboxRestrictionManager();
+ mSdkSandboxRestrictionManager.setSdkSandboxSettingsListener(mSdkSandboxSettingsListener);
// Start the handler thread.
HandlerThread handlerThread = new HandlerThread("SdkSandboxManagerServiceHandler");
@@ -408,6 +409,7 @@
private void registerBroadcastReceivers() {
registerPackageUpdateBroadcastReceiver();
+ // TODO(b/406771034): Clean up the dynamic registration of the SdkSandboxVerifierReceiver
registerVerifierBroadcastReceiver();
}
diff --git a/sdksandbox/service/java/com/android/server/sdksandbox/SdkSandboxRestrictionManager.java b/sdksandbox/service/java/com/android/server/sdksandbox/SdkSandboxRestrictionManager.java
index 596ab65..b93a194 100644
--- a/sdksandbox/service/java/com/android/server/sdksandbox/SdkSandboxRestrictionManager.java
+++ b/sdksandbox/service/java/com/android/server/sdksandbox/SdkSandboxRestrictionManager.java
@@ -25,6 +25,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.server.sdksandbox.helpers.PackageManagerHelper;
+import com.android.server.sdksandbox.verifier.SdkDexVerifier;
import java.io.PrintWriter;
import java.util.List;
@@ -42,6 +43,8 @@
private final Object mLock = new Object();
private final Injector mInjector;
+ // TODO(b/231441674) check cache of verification results
+ private final SdkDexVerifier mSdkDexVerifier;
// The key will be the client app's UID
@GuardedBy("mLock")
@@ -53,13 +56,16 @@
SdkSandboxRestrictionManager(Injector injector) {
mInjector = injector;
+ mSdkDexVerifier = mInjector.getSdkDexVerifier();
}
static class Injector {
private final Context mContext;
+ private final SdkDexVerifier mSdkDexVerifier;
Injector(Context context) {
mContext = context;
+ mSdkDexVerifier = SdkDexVerifier.getInstance();
}
PackageManagerHelper getPackageManagerHelper(int callingUid) {
@@ -69,6 +75,15 @@
int getCurrentSdkLevel() {
return Build.VERSION.SDK_INT;
}
+
+ SdkDexVerifier getSdkDexVerifier() {
+ return mSdkDexVerifier;
+ }
+ }
+
+ public void setSdkSandboxSettingsListener(
+ SdkSandboxSettingsListener sdkSandboxSettingsListener) {
+ mSdkDexVerifier.setSdkSandboxSettingsListener(sdkSandboxSettingsListener);
}
/** Cache and get the effectiveTargetSdkVersion for the sdk sandbox process */
diff --git a/sdksandbox/service/java/com/android/server/sdksandbox/SdkSandboxSettingsListener.java b/sdksandbox/service/java/com/android/server/sdksandbox/SdkSandboxSettingsListener.java
index 8c83cb8..7bb20b6 100644
--- a/sdksandbox/service/java/com/android/server/sdksandbox/SdkSandboxSettingsListener.java
+++ b/sdksandbox/service/java/com/android/server/sdksandbox/SdkSandboxSettingsListener.java
@@ -44,7 +44,12 @@
import java.util.Objects;
import java.util.Set;
-class SdkSandboxSettingsListener implements DeviceConfig.OnPropertiesChangedListener {
+/**
+ * Listens to changes in DeviceConfig flags and caches their values
+ *
+ * @hide
+ */
+public class SdkSandboxSettingsListener implements DeviceConfig.OnPropertiesChangedListener {
private static final String TAG = "SdkSandboxManager";
private static final String PROPERTY_DISABLE_SDK_SANDBOX = "disable_sdk_sandbox";
@@ -55,7 +60,8 @@
* Property to enforce restrictions for SDK sandbox processes. If the value of this property is
* {@code true}, the restrictions will be enforced.
*/
- private static final String PROPERTY_ENFORCE_RESTRICTIONS = "sdksandbox_enforce_restrictions";
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ static final String PROPERTY_ENFORCE_RESTRICTIONS = "sdksandbox_enforce_restrictions";
private static final boolean DEFAULT_VALUE_ENFORCE_RESTRICTIONS = true;
@@ -112,6 +118,12 @@
// Trivial bug fix. Enabled by default.
private static final boolean DEFAULT_VALUE_FIX_STOP_SANDBOX_DEADLOCK = true;
+ // Property to enable verification of dex files in SDK sandbox.
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ static final String PROPERTY_VERIFY_DEX_FILES = "SdkInstallChecks__verify_dex_files";
+
+ private static final boolean DEFAULT_VALUE_VERIFY_DEX_FILES = false;
+
private final Context mContext;
private final Object mLock = new Object();
private final SdkSandboxManagerService mSdkSandboxManagerService;
@@ -226,6 +238,13 @@
PROPERTY_FIX_STOP_SANDBOX_DEADLOCK,
DEFAULT_VALUE_FIX_STOP_SANDBOX_DEADLOCK);
+ @GuardedBy("mLock")
+ private boolean mVerifyDexFiles =
+ DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ADSERVICES,
+ PROPERTY_VERIFY_DEX_FILES,
+ DEFAULT_VALUE_VERIFY_DEX_FILES);
+
SdkSandboxSettingsListener(Context context, SdkSandboxManagerService sdkSandboxManagerService) {
mContext = context;
mSdkSandboxManagerService = sdkSandboxManagerService;
@@ -350,6 +369,12 @@
mSdkSandboxManagerService.onUserUnlocking(
mSdkSandboxManagerService.getCurrentUserId());
}
+ break;
+ case PROPERTY_VERIFY_DEX_FILES:
+ mVerifyDexFiles =
+ properties.getBoolean(
+ PROPERTY_VERIFY_DEX_FILES, DEFAULT_VALUE_VERIFY_DEX_FILES);
+
default:
}
if (propertyIsLogged) {
@@ -463,6 +488,13 @@
}
}
+ /** Returns the flag value gating verification of SDK libraries DEX files */
+ public boolean verifyDexFiles() {
+ synchronized (mLock) {
+ return mVerifyDexFiles;
+ }
+ }
+
/**
* Helper function to decode a proto property
*
diff --git a/sdksandbox/service/java/com/android/server/sdksandbox/SdkSandboxVerifierReceiver.java b/sdksandbox/service/java/com/android/server/sdksandbox/SdkSandboxVerifierReceiver.java
index fe36c83..93faf41 100644
--- a/sdksandbox/service/java/com/android/server/sdksandbox/SdkSandboxVerifierReceiver.java
+++ b/sdksandbox/service/java/com/android/server/sdksandbox/SdkSandboxVerifierReceiver.java
@@ -16,8 +16,6 @@
package com.android.server.sdksandbox;
-import static com.android.sdksandbox.flags.Flags.sdkSandboxVerifySdkDexFiles;
-
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -28,7 +26,6 @@
import android.os.HandlerThread;
import android.os.OutcomeReceiver;
import android.os.Process;
-import android.provider.DeviceConfig;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -67,21 +64,14 @@
}
@VisibleForTesting
- void setSdkDexVerifier(SdkDexVerifier sdkDexVerifier) {
- mSdkDexVerifier = sdkDexVerifier;
- }
-
- @VisibleForTesting
void verifySdkHandler(Context context, Intent intent, Handler handler) {
int verificationId = intent.getIntExtra(PackageManager.EXTRA_VERIFICATION_ID, -1);
- boolean isRestrictionsEnabled =
- sdkSandboxVerifySdkDexFiles()
- && DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_ADSERVICES,
- SdkSandboxManagerService.PROPERTY_ENFORCE_RESTRICTIONS,
- SdkSandboxManagerService.DEFAULT_VALUE_ENFORCE_RESTRICTIONS);
- if (!isRestrictionsEnabled) {
+ if (mSdkDexVerifier == null) {
+ mSdkDexVerifier = SdkDexVerifier.getInstance();
+ }
+
+ if (!mSdkDexVerifier.dexVerificationEnabled()) {
context.getPackageManager()
.verifyPendingInstall(verificationId, PackageManager.VERIFICATION_ALLOW);
Log.d(TAG, "Restrictions disabled. Sent VERIFICATION_ALLOW");
@@ -102,9 +92,6 @@
return;
}
- if (mSdkDexVerifier == null) {
- mSdkDexVerifier = SdkDexVerifier.getInstance();
- }
int targetSdkVersion =
packageInfo.applicationInfo != null
? packageInfo.applicationInfo.targetSdkVersion
diff --git a/sdksandbox/service/java/com/android/server/sdksandbox/verifier/SdkDexVerifier.java b/sdksandbox/service/java/com/android/server/sdksandbox/verifier/SdkDexVerifier.java
index 6192615..a664120 100644
--- a/sdksandbox/service/java/com/android/server/sdksandbox/verifier/SdkDexVerifier.java
+++ b/sdksandbox/service/java/com/android/server/sdksandbox/verifier/SdkDexVerifier.java
@@ -28,6 +28,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.sdksandbox.SdkSandboxSettingsListener;
import com.android.server.sdksandbox.proto.Verifier.AllowedApi;
import com.android.server.sdksandbox.proto.Verifier.AllowedApisList;
import com.android.server.sdksandbox.verifier.SerialDexLoader.DexSymbols;
@@ -72,6 +73,7 @@
private static SdkDexVerifier sSdkDexVerifier;
private ApiAllowlistProvider mApiAllowlistProvider;
private SerialDexLoader mDexLoader;
+ private SdkSandboxSettingsListener mSdkSandboxSettingsListener;
// Maps targetSdkVersion to its allowlist
@GuardedBy("mPlatformApiAllowlistsLock")
@@ -101,6 +103,24 @@
}
/**
+ * Sets a {@link SdkSandboxSettingsListener} to check for flags gating verification. If the
+ * settingsListener is null, verification will be disabled
+ */
+ public void setSdkSandboxSettingsListener(SdkSandboxSettingsListener settingsListener) {
+ mSdkSandboxSettingsListener = settingsListener;
+ }
+
+ /**
+ * Checks relevant DeviceConfig flags and returns true if SDK DEX files verification is enabled.
+ */
+ public boolean dexVerificationEnabled() {
+ return mSdkSandboxSettingsListener != null
+ ? mSdkSandboxSettingsListener.areRestrictionsEnforced()
+ && mSdkSandboxSettingsListener.verifyDexFiles()
+ : false;
+ }
+
+ /**
* Starts verification of the requested sdk
*
* @param sdkPath path to the sdk package to be verified
diff --git a/sdksandbox/tests/unittest/src/com/android/server/sdksandbox/SdkSandboxSettingsListenerUnitTest.java b/sdksandbox/tests/unittest/src/com/android/server/sdksandbox/SdkSandboxSettingsListenerUnitTest.java
index e0423d9..10e46d4 100644
--- a/sdksandbox/tests/unittest/src/com/android/server/sdksandbox/SdkSandboxSettingsListenerUnitTest.java
+++ b/sdksandbox/tests/unittest/src/com/android/server/sdksandbox/SdkSandboxSettingsListenerUnitTest.java
@@ -19,6 +19,7 @@
import static com.android.server.sdksandbox.SdkSandboxSettingsListener.PROPERTY_ENABLE_HSUM_SUPPORT_FOR_SDK_STORAGE;
import static com.android.server.sdksandbox.SdkSandboxSettingsListener.PROPERTY_FIX_STOP_SANDBOX_DEADLOCK;
import static com.android.server.sdksandbox.SdkSandboxSettingsListener.PROPERTY_RECONCILE_ON_VOLUME_MOUNT;
+import static com.android.server.sdksandbox.SdkSandboxSettingsListener.PROPERTY_VERIFY_DEX_FILES;
import static com.google.common.truth.Truth.assertThat;
@@ -47,6 +48,7 @@
"apply_sdk_sandbox_next_restrictions";
private static final String PROPERTY_SERVICES_ALLOWLIST =
"services_allowlist_per_targetSdkVersion";
+
private SdkSandboxSettingsListener mSdkSandboxSettingsListener;
@Before
@@ -209,6 +211,20 @@
assertThat(mSdkSandboxSettingsListener.getStopSandboxDeadlockFix()).isFalse();
}
+ @Test
+ public void testVerifyDexFiles_default() {
+ assertThat(mSdkSandboxSettingsListener.verifyDexFiles()).isFalse();
+ }
+
+ @Test
+ public void testVerifyDexFiles_update() {
+ setDeviceConfigProperty(PROPERTY_VERIFY_DEX_FILES, "true");
+ assertThat(mSdkSandboxSettingsListener.verifyDexFiles()).isTrue();
+
+ setDeviceConfigProperty(PROPERTY_VERIFY_DEX_FILES, "false");
+ assertThat(mSdkSandboxSettingsListener.verifyDexFiles()).isFalse();
+ }
+
private void verifyAllowlistEntryContents(
Services.AllowedService allowedService,
String action,
diff --git a/sdksandbox/tests/unittest/src/com/android/server/sdksandbox/SdkSandboxVerifierReceiverUnitTest.java b/sdksandbox/tests/unittest/src/com/android/server/sdksandbox/SdkSandboxVerifierReceiverUnitTest.java
index 02cecd5..7283bf7 100644
--- a/sdksandbox/tests/unittest/src/com/android/server/sdksandbox/SdkSandboxVerifierReceiverUnitTest.java
+++ b/sdksandbox/tests/unittest/src/com/android/server/sdksandbox/SdkSandboxVerifierReceiverUnitTest.java
@@ -16,6 +16,9 @@
package com.android.server.sdksandbox;
+import static com.android.server.sdksandbox.SdkSandboxSettingsListener.PROPERTY_ENFORCE_RESTRICTIONS;
+import static com.android.server.sdksandbox.SdkSandboxSettingsListener.PROPERTY_VERIFY_DEX_FILES;
+
import android.Manifest;
import android.content.Context;
import android.content.Intent;
@@ -24,24 +27,19 @@
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-import android.provider.DeviceConfig;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.dx.mockito.inline.extended.ExtendedMockito;
-import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
+import com.android.adservices.common.AdServicesFlagsSetterRule;
+import com.android.adservices.shared.testing.annotations.SetFlagTrue;
import com.android.server.sdksandbox.verifier.SdkDexVerifier;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mockito;
-import org.mockito.MockitoSession;
import java.io.File;
@@ -54,14 +52,14 @@
private static final PackageInfo FAKE_PACKAGE_INFO = new PackageInfo();
private static final Handler HANDLER = new Handler(Looper.getMainLooper());
+ private SdkSandboxSettingsListener mSdkSandboxSettingsListener;
private SdkSandboxVerifierReceiver mVerifierReceiver;
private Context mSpyContext;
private PackageManager mSpyPm;
- private SdkDexVerifier mSpyDexVerifier;
+ private SdkDexVerifier mDexVerifier;
private Handler mSpyHandler;
- @Rule(order = 0)
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+ @Rule public final AdServicesFlagsSetterRule flags = AdServicesFlagsSetterRule.newInstance();
@Before
public void setup() {
@@ -71,14 +69,14 @@
Manifest.permission.READ_DEVICE_CONFIG,
Manifest.permission.PACKAGE_VERIFICATION_AGENT);
- StaticMockitoSessionBuilder mockitoSessionBuilder =
- ExtendedMockito.mockitoSession().spyStatic(DeviceConfig.class).initMocks(this);
mVerifierReceiver = new SdkSandboxVerifierReceiver();
- mSpyDexVerifier = Mockito.spy(SdkDexVerifier.getInstance());
- mVerifierReceiver.setSdkDexVerifier(mSpyDexVerifier);
-
Context context = InstrumentationRegistry.getInstrumentation().getContext();
mSpyContext = Mockito.spy(context);
+ mSdkSandboxSettingsListener = new SdkSandboxSettingsListener(mSpyContext, null);
+
+ mDexVerifier = SdkDexVerifier.getInstance();
+ mDexVerifier.setSdkSandboxSettingsListener(mSdkSandboxSettingsListener);
+
PackageManager pm = mSpyContext.getPackageManager();
mSpyPm = Mockito.spy(pm);
mSpyHandler = Mockito.spy(HANDLER);
@@ -88,47 +86,32 @@
.thenReturn(FAKE_PACKAGE_INFO);
}
- @Ignore("TODO(b/231441674): This test relies on a flag which is planned to be rolledback")
+ @SetFlagTrue(PROPERTY_ENFORCE_RESTRICTIONS)
+ @SetFlagTrue(PROPERTY_VERIFY_DEX_FILES)
@Test
public void verifierBroadcastReceived_startsDexParsing() {
- MockitoSession staticMockSession = null;
- try {
- staticMockSession =
- ExtendedMockito.mockitoSession().spyStatic(DeviceConfig.class).startMocking();
- ExtendedMockito.when(
- DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_ADSERVICES,
- SdkSandboxManagerService.PROPERTY_ENFORCE_RESTRICTIONS,
- SdkSandboxManagerService.DEFAULT_VALUE_ENFORCE_RESTRICTIONS))
- .thenReturn(true);
+ mVerifierReceiver.verifySdkHandler(mSpyContext, VERIFY_INTENT, mSpyHandler);
- mVerifierReceiver.verifySdkHandler(mSpyContext, VERIFY_INTENT, mSpyHandler);
-
- Mockito.verify(mSpyHandler, Mockito.times(1)).post(Mockito.any());
- } finally {
- staticMockSession.finishMocking();
- }
+ Mockito.verify(mSpyHandler, Mockito.times(1)).post(Mockito.any());
}
- @Ignore("TODO(b/231441674): This test relies on a flag which is planned to be rolledback")
@Test
public void verifierBroadcastReceived_doesNotStartDexParsing() {
- MockitoSession staticMockSession = null;
- try {
- staticMockSession =
- ExtendedMockito.mockitoSession().spyStatic(DeviceConfig.class).startMocking();
- ExtendedMockito.when(
- DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_ADSERVICES,
- SdkSandboxManagerService.PROPERTY_ENFORCE_RESTRICTIONS,
- SdkSandboxManagerService.DEFAULT_VALUE_ENFORCE_RESTRICTIONS))
- .thenReturn(false);
+ flags.setFlag(PROPERTY_ENFORCE_RESTRICTIONS, false);
+ flags.setFlag(PROPERTY_VERIFY_DEX_FILES, false);
+ mVerifierReceiver.verifySdkHandler(mSpyContext, VERIFY_INTENT, mSpyHandler);
- mVerifierReceiver.verifySdkHandler(mSpyContext, VERIFY_INTENT, mSpyHandler);
+ Mockito.verify(mSpyHandler, Mockito.times(0)).post(Mockito.any());
- Mockito.verify(mSpyHandler, Mockito.times(0)).post(Mockito.any());
- } finally {
- staticMockSession.finishMocking();
- }
+ flags.setFlag(PROPERTY_ENFORCE_RESTRICTIONS, true);
+ mVerifierReceiver.verifySdkHandler(mSpyContext, VERIFY_INTENT, mSpyHandler);
+
+ Mockito.verify(mSpyHandler, Mockito.times(0)).post(Mockito.any());
+
+ flags.setFlag(PROPERTY_ENFORCE_RESTRICTIONS, false);
+ flags.setFlag(PROPERTY_VERIFY_DEX_FILES, true);
+ mVerifierReceiver.verifySdkHandler(mSpyContext, VERIFY_INTENT, mSpyHandler);
+
+ Mockito.verify(mSpyHandler, Mockito.times(0)).post(Mockito.any());
}
}