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());
     }
 }