CTS tests for security logging delegate

Test: The following were run:
  atest com.android.cts.devicepolicy.OrgOwnedProfileOwnerTest#testSecurityLogging
  atest com.android.cts.devicepolicy.OrgOwnedProfileOwnerTest#testSecurityLoggingDelegate
  atest com.android.cts.devicepolicy.MixedDeviceOwnerTest#testSecurityLoggingWithSingleUser
  atest com.android.cts.devicepolicy.MixedDeviceOwnerTest#testSecurityLoggingDelegate

Bug: 165905995

Change-Id: Ic49dca6b903843738c066d19212cbc5ce39f8a6e
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/DelegateTestUtils.java b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/DelegateTestUtils.java
index 5a84fde..be2ad73 100644
--- a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/DelegateTestUtils.java
+++ b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/DelegateTestUtils.java
@@ -15,18 +15,30 @@
  */
 package com.android.cts.delegate;
 
+import static android.app.admin.SecurityLog.TAG_KEY_DESTRUCTION;
+import static android.app.admin.SecurityLog.TAG_KEY_GENERATED;
+
+import static com.google.common.truth.Truth.assertThat;
+
 import static junit.framework.Assert.fail;
 
 import android.app.admin.DelegatedAdminReceiver;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.NetworkEvent;
+import android.app.admin.SecurityLog.SecurityEvent;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Process;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
 import android.test.MoreAsserts;
 import android.util.Log;
 
 import junit.framework.Assert;
 
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
@@ -36,6 +48,13 @@
  * Utils class for delegation tests.
  */
 public class DelegateTestUtils {
+    // Indices of various fields in SecurityEvent payload.
+    private static final int SUCCESS_INDEX = 0;
+    private static final int ALIAS_INDEX = 1;
+    private static final int UID_INDEX = 2;
+
+    // Value that indicates success in events that have corresponding field in their payload.
+    private static final int SUCCESS_VALUE = 1;
 
     @FunctionalInterface
     public interface ExceptionRunnable {
@@ -101,4 +120,89 @@
         }
         Assert.fail("Expected " + expectedExceptionType.getName() + " was not thrown");
     }
+
+    /**
+     * Generates a key for the given key alias, asserts it was created successfully
+     */
+    public static void testGenerateKey(String keyAlias) throws Exception {
+        final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
+        generator.initialize(
+                new KeyGenParameterSpec.Builder(keyAlias, KeyProperties.PURPOSE_SIGN).build());
+        final KeyPair keyPair = generator.generateKeyPair();
+        assertThat(keyPair).isNotNull();
+    }
+
+    /**
+     * Deletes a key for the given key alias
+     */
+    public static void deleteKey(String keyAlias) throws Exception {
+        final KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
+        ks.load(null);
+        ks.deleteEntry(keyAlias);
+    }
+
+
+    /**
+     * Fetches the available security events
+     */
+    public static List<SecurityEvent> getSecurityEvents(DevicePolicyManager dpm)
+            throws Exception {
+        List<SecurityEvent> events = null;
+        // Retry once after seeping for 1 second, in case "dpm force-security-logs" hasn't taken
+        // effect just yet.
+        for (int i = 0; i < 5 && events == null; i++) {
+            events = dpm.retrieveSecurityLogs(null);
+            if (events == null) Thread.sleep(1000);
+        }
+
+        return events;
+    }
+
+    /**
+     * Verifies that the expected keystore events generated by {@link #testGenerateKey} are
+     * present
+     */
+    public static void verifyKeystoreEventsPresent(String generatedKeyAlias,
+            List<SecurityEvent> securityEvents) {
+        int receivedKeyGenerationEvents = 0;
+        int receivedKeyDeletionEvents = 0;
+
+        for (final SecurityEvent currentEvent : securityEvents) {
+            if (currentEvent.getTag() == TAG_KEY_GENERATED) {
+                verifyKeyEvent(currentEvent, generatedKeyAlias);
+                receivedKeyGenerationEvents++;
+            }
+
+            if (currentEvent.getTag() == TAG_KEY_DESTRUCTION) {
+                verifyKeyEvent(currentEvent, generatedKeyAlias);
+                receivedKeyDeletionEvents++;
+            }
+        }
+
+        assertThat(receivedKeyGenerationEvents).isEqualTo(1);
+        assertThat(receivedKeyDeletionEvents).isEqualTo(1);
+    }
+
+    /**
+     * Verifies that a security event represents a successful key modification event for
+     * keyAlias
+     */
+    private static void verifyKeyEvent(SecurityEvent event, String keyAlias) {
+        assertThat(getInt(event, SUCCESS_INDEX)).isEqualTo(SUCCESS_VALUE);
+        assertThat(getString(event, ALIAS_INDEX)).contains(keyAlias);
+        assertThat(getInt(event, UID_INDEX)).isEqualTo(Process.myUid());
+    }
+
+    private static Object getDatum(SecurityEvent event, int index) {
+        final Object[] dataArray = (Object[]) event.getData();
+        return dataArray[index];
+    }
+
+    private static String getString(SecurityEvent event, int index) {
+        return (String) getDatum(event, index);
+    }
+
+    private static int getInt(SecurityEvent event, int index) {
+        return (Integer) getDatum(event, index);
+    }
 }
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/SecurityLoggingDelegateTest.java b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/SecurityLoggingDelegateTest.java
new file mode 100644
index 0000000..e924d41
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/SecurityLoggingDelegateTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.delegate;
+
+import static com.android.cts.delegate.DelegateTestUtils.assertExpectException;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.SecurityLog.SecurityEvent;
+import android.content.Context;
+import android.support.test.uiautomator.UiDevice;
+import android.test.InstrumentationTestCase;
+
+import androidx.test.InstrumentationRegistry;
+
+import java.util.List;
+
+/**
+ * Tests that a delegate app with DELEGATION_SECURITY_LOGGING is able to control and access
+ * security logging.
+ */
+public class SecurityLoggingDelegateTest extends InstrumentationTestCase {
+
+    private static final String TAG = "SecurityLoggingDelegateTest";
+
+    private Context mContext;
+    private DevicePolicyManager mDpm;
+    private UiDevice mDevice;
+
+    private static final String GENERATED_KEY_ALIAS = "generated_key_alias";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        mContext = getInstrumentation().getContext();
+        mDpm = mContext.getSystemService(DevicePolicyManager.class);
+    }
+
+    public void testCannotAccessApis()throws Exception {
+        assertExpectException(SecurityException.class, null,
+                () -> mDpm.isSecurityLoggingEnabled(null));
+
+        assertExpectException(SecurityException.class, null,
+                () -> mDpm.setSecurityLoggingEnabled(null, true));
+
+        assertExpectException(SecurityException.class, null,
+                () -> mDpm.retrieveSecurityLogs(null));
+    }
+
+    /**
+     * Test: Test enabling security logging.
+     * This test has a side effect: security logging is enabled after its execution.
+     */
+    public void testEnablingSecurityLogging() {
+        mDpm.setSecurityLoggingEnabled(null, true);
+
+        assertThat(mDpm.isSecurityLoggingEnabled(null)).isTrue();
+    }
+
+    /**
+     * Generates security events related to Keystore
+     */
+    public void testGenerateLogs() throws Exception {
+        try {
+            DelegateTestUtils.testGenerateKey(GENERATED_KEY_ALIAS);
+        } finally {
+            DelegateTestUtils.deleteKey(GENERATED_KEY_ALIAS);
+        }
+    }
+
+    /**
+     * Test: retrieves security logs and verifies that all events generated as a result of host
+     * side actions and by {@link #testGenerateLogs()} are there.
+     */
+    public void testVerifyGeneratedLogs() throws Exception {
+        final List<SecurityEvent> events = DelegateTestUtils.getSecurityEvents(mDpm);
+        DelegateTestUtils.verifyKeystoreEventsPresent(GENERATED_KEY_ALIAS, events);
+    }
+
+    /**
+     * Test: retrieving security logs should be rate limited - subsequent attempts should return
+     * null.
+     */
+    public void testSecurityLoggingRetrievalRateLimited() {
+        final List<SecurityEvent> logs = mDpm.retrieveSecurityLogs(null);
+        // if logs is null it means that that attempt was rate limited => test PASS
+        if (logs != null) {
+            assertThat(mDpm.retrieveSecurityLogs(null)).isNull();
+            assertThat(mDpm.retrieveSecurityLogs(null)).isNull();
+        }
+    }
+
+    /**
+     * Test: Test disaling security logging.
+     * This test has a side effect: security logging is disabled after its execution.
+     */
+    public void testDisablingSecurityLogging() {
+        mDpm.setSecurityLoggingEnabled(null, false);
+
+        assertThat(mDpm.isSecurityLoggingEnabled(null)).isFalse();
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/WorkProfileSecurityLoggingDelegateTest.java b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/WorkProfileSecurityLoggingDelegateTest.java
new file mode 100644
index 0000000..e660d1b
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/WorkProfileSecurityLoggingDelegateTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.delegate;
+
+import static com.android.cts.delegate.DelegateTestUtils.assertExpectException;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.SecurityLog.SecurityEvent;
+import android.content.Context;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class WorkProfileSecurityLoggingDelegateTest {
+
+    private static final String TAG = "WorkProfileSecurityLoggingDelegateTest";
+    private static final String CTS_APP_PACKAGE_NAME = "com.android.cts.delegate";
+    private static final String GENERATED_KEY_ALIAS = "generated_key_alias";
+
+    private Context mContext;
+    private DevicePolicyManager mDpm;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getContext();
+        mDpm = mContext.getSystemService(DevicePolicyManager.class);
+    }
+
+    @Test
+    public void testCannotAccessApis() {
+        assertExpectException(SecurityException.class, null,
+                () -> mDpm.isSecurityLoggingEnabled(null));
+
+        assertExpectException(SecurityException.class, null,
+                () -> mDpm.setSecurityLoggingEnabled(null, true));
+
+        assertExpectException(SecurityException.class, null,
+                () -> mDpm.retrieveSecurityLogs(null));
+    }
+
+    /**
+     * Test: Test enabling security logging.
+     * This test has a side effect: security logging is enabled after its execution.
+     */
+    @Test
+    public void testEnablingSecurityLogging() {
+        mDpm.setSecurityLoggingEnabled(null, true);
+
+        assertThat(mDpm.isSecurityLoggingEnabled(null)).isTrue();
+    }
+
+    /**
+     * Generates security events related to Keystore
+     */
+    @Test
+    public void testGenerateLogs() throws Exception {
+        try {
+            DelegateTestUtils.testGenerateKey(GENERATED_KEY_ALIAS);
+        } finally {
+            DelegateTestUtils.deleteKey(GENERATED_KEY_ALIAS);
+        }
+    }
+
+    /**
+     * Test: retrieves security logs and verifies that all events generated as a result of host
+     * side actions and by {@link #testGenerateLogs()} are there.
+     */
+    @Test
+    public void testVerifyGeneratedLogs() throws Exception {
+        final List<SecurityEvent> events = DelegateTestUtils.getSecurityEvents(mDpm);
+        DelegateTestUtils.verifyKeystoreEventsPresent(GENERATED_KEY_ALIAS, events);
+    }
+
+    /**
+     * Test: retrieving security logs should be rate limited - subsequent attempts should return
+     * null.
+     */
+    @Test
+    public void testSecurityLoggingRetrievalRateLimited() {
+        final List<SecurityEvent> logs = mDpm.retrieveSecurityLogs(null);
+        // if logs is null it means that that attempt was rate limited => test PASS
+        if (logs != null) {
+            assertThat(mDpm.retrieveSecurityLogs(null)).isNull();
+            assertThat(mDpm.retrieveSecurityLogs(null)).isNull();
+        }
+    }
+
+    /**
+     * Test: Test disaling security logging.
+     * This test has a side effect: security logging is disabled after its execution.
+     */
+    @Test
+    public void testDisablingSecurityLogging() {
+        mDpm.setSecurityLoggingEnabled(null, false);
+
+        assertThat(mDpm.isSecurityLoggingEnabled(null)).isFalse();
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java
index 27b29f0..5def362 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java
@@ -22,6 +22,7 @@
 import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_SELECTION;
 import static android.app.admin.DevicePolicyManager.DELEGATION_ENABLE_SYSTEM_APP;
 import static android.app.admin.DevicePolicyManager.DELEGATION_NETWORK_LOGGING;
+import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
 import static android.app.admin.DevicePolicyManager.EXTRA_DELEGATION_SCOPES;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -188,7 +189,8 @@
     }
 
     public void testDeviceOwnerOrManagedPoOnlyDelegations() throws Exception {
-        final String doOrManagedPoDelegations[] = {DELEGATION_NETWORK_LOGGING};
+        final String [] doOrManagedPoDelegations =
+                { DELEGATION_NETWORK_LOGGING, DELEGATION_SECURITY_LOGGING };
         final boolean isDeviceOwner = mDevicePolicyManager.isDeviceOwnerApp(
                 mContext.getPackageName());
         final boolean isManagedProfileOwner = mDevicePolicyManager.getProfileOwner() != null
@@ -214,6 +216,7 @@
                 DELEGATION_CERT_SELECTION));
         if (mDevicePolicyManager.isDeviceOwnerApp(mContext.getPackageName())) {
             exclusiveDelegations.add(DELEGATION_NETWORK_LOGGING);
+            exclusiveDelegations.add(DELEGATION_SECURITY_LOGGING);
         }
         for (String scope : exclusiveDelegations) {
             testExclusiveDelegation(scope);
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecurityLoggingTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecurityLoggingTest.java
index 8c4510d..1a67710 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecurityLoggingTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecurityLoggingTest.java
@@ -61,6 +61,7 @@
 import static com.android.cts.devicepolicy.TestCertificates.TEST_CA_SUBJECT;
 
 import static com.google.common.collect.ImmutableList.of;
+import static com.google.common.truth.Truth.assertThat;
 
 import android.app.admin.SecurityLog.SecurityEvent;
 import android.content.Context;
@@ -102,6 +103,9 @@
     private static final String PREF_NAME = "batchIds";
     // system/core/liblog/event.logtags: 1006  liblog (dropped|1)
     private static final int TAG_LIBLOG_DROPPED = 1006;
+    private static final String DELEGATE_APP_PKG = "com.android.cts.delegate";
+    private static final String DELEGATION_SECURITY_LOGGING = "delegation-security-logging";
+
 
     // For brevity.
     private static final Class<String> S = String.class;
@@ -541,6 +545,23 @@
         }
     }
 
+    public void testSetDelegateScope_delegationSecurityLogging() {
+        mDevicePolicyManager.setDelegatedScopes(ADMIN_RECEIVER_COMPONENT, DELEGATE_APP_PKG,
+                Arrays.asList(DELEGATION_SECURITY_LOGGING));
+
+        assertThat(mDevicePolicyManager.getDelegatedScopes(
+                ADMIN_RECEIVER_COMPONENT, DELEGATE_APP_PKG)).contains(DELEGATION_SECURITY_LOGGING);
+    }
+
+    public void testSetDelegateScope_noDelegation() {
+        mDevicePolicyManager.setDelegatedScopes(ADMIN_RECEIVER_COMPONENT, DELEGATE_APP_PKG,
+                Arrays.asList());
+
+        assertThat(mDevicePolicyManager.getDelegatedScopes(
+                ADMIN_RECEIVER_COMPONENT, DELEGATE_APP_PKG))
+                .doesNotContain(DELEGATION_SECURITY_LOGGING);
+    }
+
     private void generateKey(String keyAlias) throws Exception {
         final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
         generator.initialize(
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
index 142f60c..2d2c5c8 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
@@ -361,6 +361,61 @@
     }
 
     @Test
+    public void testSecurityLoggingDelegate() throws Exception {
+        installAppAsUser(DELEGATE_APP_APK, mUserId);
+        try {
+            // Test that the delegate cannot access the logs already
+            runDeviceTestsAsUser(DELEGATE_APP_PKG, ".SecurityLoggingDelegateTest",
+                    "testCannotAccessApis", mUserId);
+
+            // Set security logging delegate
+            runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".SecurityLoggingTest",
+                    "testSetDelegateScope_delegationSecurityLogging", mUserId);
+
+            runSecurityLoggingTests(DELEGATE_APP_PKG,
+                    ".SecurityLoggingDelegateTest");
+        } finally {
+            // Remove security logging delegate
+            runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".SecurityLoggingTest",
+                    "testSetDelegateScope_noDelegation", mUserId);
+        }
+    }
+
+    private void runSecurityLoggingTests(String packageName, String testClassName)
+            throws Exception {
+        // Backup stay awake setting because testGenerateLogs() will turn it off.
+        final String stayAwake = getDevice().getSetting("global", "stay_on_while_plugged_in");
+        try {
+            // Turn logging on.
+            runDeviceTestsAsUser(packageName, testClassName,
+                    "testEnablingSecurityLogging", mUserId);
+            // Reboot to ensure ro.device_owner is set to true in logd and logging is on.
+            rebootAndWaitUntilReady();
+            waitForUserUnlock(mUserId);
+
+            // Generate various types of events on device side and check that they are logged.
+            runDeviceTestsAsUser(packageName, testClassName,
+                    "testGenerateLogs", mUserId);
+            getDevice().executeShellCommand("whoami"); // Generate adb command securty event
+            getDevice().executeShellCommand("dpm force-security-logs");
+            runDeviceTestsAsUser(packageName, testClassName,
+                    "testVerifyGeneratedLogs", mUserId);
+
+            // Immediately attempting to fetch events again should fail.
+            runDeviceTestsAsUser(packageName, testClassName,
+                    "testSecurityLoggingRetrievalRateLimited", mUserId);
+        } finally {
+            // Turn logging off.
+            runDeviceTestsAsUser(packageName, testClassName,
+                    "testDisablingSecurityLogging", mUserId);
+            // Restore stay awake setting.
+            if (stayAwake != null) {
+                getDevice().setSetting("global", "stay_on_while_plugged_in", stayAwake);
+            }
+        }
+    }
+
+    @Test
     public void testLocationPermissionGrantNotifies() throws Exception {
         installAppPermissionAppAsUser();
         configureNotificationListener();
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
index 94f526f..556f6ac 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
@@ -228,30 +228,56 @@
 
     @Test
     public void testSecurityLogging() throws Exception {
+        installAppAsUser(DEVICE_ADMIN_APK, mPrimaryUserId);
+        testSecurityLoggingOnWorkProfile(DEVICE_ADMIN_PKG, ".SecurityLoggingTest");
+    }
+
+    @Test
+    public void testSecurityLoggingDelegate() throws Exception {
+        installAppAsUser(DELEGATE_APP_APK, mUserId);
+        installAppAsUser(DEVICE_ADMIN_APK, mPrimaryUserId);
+        try {
+            runDeviceTestsAsUser(DELEGATE_APP_PKG, ".WorkProfileSecurityLoggingDelegateTest",
+                    "testCannotAccessApis", mUserId);
+            // Set security logging delegate
+            runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".SecurityLoggingTest",
+                    "testSetDelegateScope_delegationSecurityLogging", mUserId);
+
+            testSecurityLoggingOnWorkProfile(DELEGATE_APP_PKG,
+                    ".WorkProfileSecurityLoggingDelegateTest");
+        } finally {
+            // Remove security logging delegate
+            runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".SecurityLoggingTest",
+                    "testSetDelegateScope_noDelegation", mUserId);
+        }
+    }
+
+    private void testSecurityLoggingOnWorkProfile(String packageName, String testClassName)
+            throws Exception {
         // Backup stay awake setting because testGenerateLogs() will turn it off.
         final String stayAwake = getDevice().getSetting("global", "stay_on_while_plugged_in");
         try {
             // Turn logging on.
-            runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".SecurityLoggingTest",
+            runDeviceTestsAsUser(packageName, testClassName,
                     "testEnablingSecurityLogging", mUserId);
             // Reboot to ensure ro.device_owner is set to true in logd and logging is on.
             rebootAndWaitUntilReady();
             waitForUserUnlock(mUserId);
 
             // Generate various types of events on device side and check that they are logged.
-            runDeviceTestsAsUser(DEVICE_ADMIN_PKG,".SecurityLoggingTest",
+            runDeviceTestsAsUser(packageName, testClassName,
                     "testGenerateLogs", mUserId);
             getDevice().executeShellCommand("whoami"); // Generate adb command securty event
             getDevice().executeShellCommand("dpm force-security-logs");
-            runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".SecurityLoggingTest",
+            runDeviceTestsAsUser(packageName, testClassName,
                     "testVerifyGeneratedLogs", mUserId);
 
             // Immediately attempting to fetch events again should fail.
-            runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".SecurityLoggingTest",
+            runDeviceTestsAsUser(packageName, testClassName,
                     "testSecurityLoggingRetrievalRateLimited", mUserId);
         } finally {
             // Turn logging off.
-            runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".SecurityLoggingTest",
+            runDeviceTestsAsUser(packageName, testClassName,
                     "testDisablingSecurityLogging", mUserId);
             // Restore stay awake setting.
             if (stayAwake != null) {