Loading core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java +4 −4 Original line number Diff line number Diff line Loading @@ -19,10 +19,10 @@ package android.security.intrusiondetection; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.app.admin.ConnectEvent; import android.app.admin.DnsEvent; import android.app.admin.SecurityLog.SecurityEvent; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.security.Flags; Loading Loading @@ -223,13 +223,13 @@ public final class IntrusionDetectionEvent implements Parcelable { out.writeInt(mType); switch (mType) { case SECURITY_EVENT: out.writeParcelable(mSecurityEvent, flags); mSecurityEvent.writeToParcel(out, flags); break; case NETWORK_EVENT_DNS: out.writeParcelable(mNetworkEventDns, flags); mNetworkEventDns.writeToParcel(out, flags); break; case NETWORK_EVENT_CONNECT: out.writeParcelable(mNetworkEventConnect, flags); mNetworkEventConnect.writeToParcel(out, flags); break; default: throw new IllegalArgumentException("Invalid event type: " + mType); Loading services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java +1 −1 Original line number Diff line number Diff line Loading @@ -62,7 +62,7 @@ public class DataAggregator { /** Initialize DataSources */ private void initialize() { mDataSources.add(new SecurityLogSource(mContext, this)); mDataSources.add(new NetworkLogSource(mContext, this)); mDataSources.add(new NetworkLogSource(this)); } /** Loading services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java +1 −3 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.server.security.intrusiondetection; import android.app.admin.ConnectEvent; import android.app.admin.DnsEvent; import android.content.Context; import android.content.pm.PackageManagerInternal; import android.net.IIpConnectivityMetrics; import android.net.INetdEventCallback; Loading @@ -44,8 +43,7 @@ public class NetworkLogSource implements DataSource { private IIpConnectivityMetrics mIpConnectivityMetrics; private long mId; public NetworkLogSource(Context context, DataAggregator dataAggregator) throws SecurityException { public NetworkLogSource(DataAggregator dataAggregator) throws SecurityException { mDataAggregator = dataAggregator; mPm = LocalServices.getService(PackageManagerInternal.class); mId = 0; Loading services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java +9 −6 Original line number Diff line number Diff line Loading @@ -19,14 +19,15 @@ package com.android.server.security.intrusiondetection; import android.Manifest.permission; import android.annotation.RequiresPermission; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.SecurityLog.SecurityEvent; import android.content.Context; import android.security.intrusiondetection.IntrusionDetectionEvent; import android.util.Slog; import com.android.server.LocalServices; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.function.Consumer; import java.util.stream.Collectors; Loading @@ -36,13 +37,13 @@ public class SecurityLogSource implements DataSource { private SecurityEventCallback mEventCallback; private DevicePolicyManager mDpm; private Executor mExecutor; private DevicePolicyManagerInternal mDpmInternal; private DataAggregator mDataAggregator; public SecurityLogSource(Context context, DataAggregator dataAggregator) { mDataAggregator = dataAggregator; mDpm = context.getSystemService(DevicePolicyManager.class); mExecutor = Executors.newSingleThreadExecutor(); mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class); mEventCallback = new SecurityEventCallback(); } Loading @@ -50,12 +51,13 @@ public class SecurityLogSource implements DataSource { @RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void enable() { enableAuditLog(); mDpm.setAuditLogEventCallback(mExecutor, mEventCallback); mDpmInternal.setInternalEventsCallback(mEventCallback); } @Override @RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void disable() { mDpmInternal.setInternalEventsCallback(null); disableAuditLog(); } Loading @@ -82,10 +84,11 @@ public class SecurityLogSource implements DataSource { @Override public void accept(List<SecurityEvent> events) { if (events.size() == 0) { if (events == null || events.size() == 0) { Slog.w(TAG, "No events received; caller may not be authorized"); return; } List<IntrusionDetectionEvent> intrusionDetectionEvents = events.stream() .filter(event -> event != null) Loading services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java +15 −163 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.server.security.intrusiondetection; import static android.Manifest.permission.BIND_INTRUSION_DETECTION_EVENT_TRANSPORT_SERVICE; import static android.Manifest.permission.INTERNET; import static android.Manifest.permission.MANAGE_INTRUSION_DETECTION_STATE; import static android.Manifest.permission.READ_INTRUSION_DETECTION_STATE; Loading @@ -28,7 +27,6 @@ import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; Loading @@ -37,8 +35,8 @@ import static org.mockito.Mockito.verify; import android.annotation.SuppressLint; import android.app.admin.ConnectEvent; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.DnsEvent; import android.app.admin.SecurityLog; import android.app.admin.SecurityLog.SecurityEvent; import android.content.ComponentName; import android.content.Context; Loading @@ -53,37 +51,22 @@ import android.os.test.TestLooper; import android.security.intrusiondetection.IIntrusionDetectionServiceCommandCallback; import android.security.intrusiondetection.IIntrusionDetectionServiceStateCallback; import android.security.intrusiondetection.IntrusionDetectionEvent; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; import android.util.Log; import androidx.test.core.app.ApplicationProvider; import com.android.bedstead.harrier.BedsteadJUnit4; import com.android.bedstead.multiuser.annotations.RequireRunOnSystemUser; import com.android.bedstead.nene.TestApis; import com.android.bedstead.nene.devicepolicy.DeviceOwner; import com.android.bedstead.permissions.CommonPermissions; import com.android.bedstead.permissions.PermissionContext; import com.android.bedstead.permissions.annotations.EnsureHasPermission; import com.android.coretests.apps.testapp.LocalIntrusionDetectionEventTransport; import com.android.server.ServiceThread; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.security.GeneralSecurityException; 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; Loading @@ -107,7 +90,6 @@ public class IntrusionDetectionServiceTest { private static final int ERROR_DATA_SOURCE_UNAVAILABLE = IIntrusionDetectionServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE; private static DeviceOwner sDeviceOwner; private Context mContext; private IntrusionDetectionEventTransportConnection mIntrusionDetectionEventTransportConnection; Loading @@ -124,6 +106,8 @@ public class IntrusionDetectionServiceTest { "com.android.coretests.apps.testapp"; private static final String TEST_SERVICE = TEST_PKG + ".TestLoggingService"; DevicePolicyManagerInternal mDevicePolicyManagerInternal; @SuppressLint("VisibleForTests") @Before public void setUp() throws Exception { Loading Loading @@ -189,6 +173,7 @@ public class IntrusionDetectionServiceTest { } @Test @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void testAddStateCallback_Disabled_TwoStateCallbacks() throws RemoteException { StateCallback scb1 = new StateCallback(); assertEquals(STATE_UNKNOWN, scb1.mState); Loading @@ -204,7 +189,7 @@ public class IntrusionDetectionServiceTest { } @Test @Ignore("Unit test does not run as system service UID") @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void testRemoveStateCallback() throws RemoteException { mIntrusionDetectionService.setState(STATE_DISABLED); StateCallback scb1 = new StateCallback(); Loading @@ -220,15 +205,19 @@ public class IntrusionDetectionServiceTest { mIntrusionDetectionService.getBinderService().removeStateCallback(scb2); CommandCallback ccb = new CommandCallback(); // Enable will fail; caller does not run as system server. doNothing().when(mDataAggregator).enable(); mIntrusionDetectionService.getBinderService().enable(ccb); mTestLooper.dispatchAll(); assertEquals(STATE_ENABLED, scb1.mState); assertEquals(STATE_DISABLED, scb2.mState); assertNull(ccb.mErrorCode); } @Ignore("Unit test does not run as system service UID") @Test @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void testEnable_FromDisabled_TwoStateCallbacks() throws RemoteException { mIntrusionDetectionService.setState(STATE_DISABLED); StateCallback scb1 = new StateCallback(); Loading @@ -243,6 +232,9 @@ public class IntrusionDetectionServiceTest { CommandCallback ccb = new CommandCallback(); mIntrusionDetectionService.getBinderService().enable(ccb); // Enable will fail; caller does not run as system server. doNothing().when(mDataAggregator).enable(); mTestLooper.dispatchAll(); verify(mDataAggregator, times(1)).enable(); Loading Loading @@ -319,7 +311,7 @@ public class IntrusionDetectionServiceTest { assertNull(ccb.mErrorCode); } @Ignore("Enable once the IntrusionDetectionEventTransportConnection is ready") @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) @Test public void testEnable_FromDisable_TwoStateCallbacks_TransportUnavailable() throws RemoteException { Loading Loading @@ -389,146 +381,6 @@ public class IntrusionDetectionServiceTest { assertNotNull(receivedEvents.get(2).getDnsEvent()); } @Test @Ignore("Unit test does not run as system service UID") @RequireRunOnSystemUser @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void testDataAggregator_AddSecurityEvent() throws Exception { mIntrusionDetectionService.setState(STATE_ENABLED); ServiceThread mockThread = spy(ServiceThread.class); mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread); // SecurityLogging generates a number of events and callbacks, so create a latch to wait for // the given event. String eventString = this.getClass().getName() + ".testSecurityEvent"; final CountDownLatch latch = new CountDownLatch(1); // TODO: Replace this mock when the IntrusionDetectionEventTransportConnection is ready. doAnswer( new Answer<Boolean>() { @Override public Boolean answer(InvocationOnMock input) { List<IntrusionDetectionEvent> receivedEvents = (List<IntrusionDetectionEvent>) input.getArguments()[0]; for (IntrusionDetectionEvent event : receivedEvents) { if (event.getType() == IntrusionDetectionEvent.SECURITY_EVENT) { SecurityEvent securityEvent = event.getSecurityEvent(); Object[] eventData = (Object[]) securityEvent.getData(); if (securityEvent.getTag() == SecurityLog.TAG_KEY_GENERATED && eventData[1].equals(eventString)) { latch.countDown(); } } } return true; } }) .when(mIntrusionDetectionEventTransportConnection).addData(any()); mDataAggregator.enable(); // Generate the security event. generateSecurityEvent(eventString); TestApis.devicePolicy().forceSecurityLogs(); // Verify the event is received. mTestLooper.startAutoDispatch(); assertTrue(latch.await(1, TimeUnit.SECONDS)); mTestLooper.stopAutoDispatch(); mDataAggregator.disable(); } @Test @RequireRunOnSystemUser @Ignore("Unit test does not run as system service UID") @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void testDataAggregator_AddNetworkEvent() throws Exception { mIntrusionDetectionService.setState(STATE_ENABLED); ServiceThread mockThread = spy(ServiceThread.class); mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread); // Network logging may log multiple and callbacks, so create a latch to wait for // the given event. // eventServer must be a valid domain to generate a network log event. String eventServer = "google.com"; final CountDownLatch latch = new CountDownLatch(1); // TODO: Replace this mock when the IntrusionDetectionEventTransportConnection is ready. doAnswer( new Answer<Boolean>() { @Override public Boolean answer(InvocationOnMock input) { List<IntrusionDetectionEvent> receivedEvents = (List<IntrusionDetectionEvent>) input.getArguments()[0]; for (IntrusionDetectionEvent event : receivedEvents) { if (event.getType() == IntrusionDetectionEvent.NETWORK_EVENT_DNS) { DnsEvent dnsEvent = event.getDnsEvent(); if (dnsEvent.getHostname().equals(eventServer)) { latch.countDown(); } } } return true; } }) .when(mIntrusionDetectionEventTransportConnection).addData(any()); mDataAggregator.enable(); // Generate the network event. generateNetworkEvent(eventServer); TestApis.devicePolicy().forceNetworkLogs(); // Verify the event is received. mTestLooper.startAutoDispatch(); assertTrue(latch.await(1, TimeUnit.SECONDS)); mTestLooper.stopAutoDispatch(); mDataAggregator.disable(); } /** Emits a given string into security log (if enabled). */ private void generateSecurityEvent(String eventString) throws IllegalArgumentException, GeneralSecurityException, IOException { if (eventString == null || eventString.isEmpty()) { throw new IllegalArgumentException( "Error generating security event: eventString must not be empty"); } final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore"); keyGen.initialize( new KeyGenParameterSpec.Builder(eventString, KeyProperties.PURPOSE_SIGN).build()); // Emit key generation event. final KeyPair keyPair = keyGen.generateKeyPair(); assertNotNull(keyPair); final KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); ks.load(null); // Emit key destruction event. ks.deleteEntry(eventString); } /** Emits a given string into network log (if enabled). */ private void generateNetworkEvent(String server) throws IllegalArgumentException, IOException { if (server == null || server.isEmpty()) { throw new IllegalArgumentException( "Error generating network event: server must not be empty"); } HttpURLConnection urlConnection = null; int connectionTimeoutMS = 2_000; try (PermissionContext p = TestApis.permissions().withPermission(INTERNET)) { final URL url = new URL("http://" + server); urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setConnectTimeout(connectionTimeoutMS); urlConnection.setReadTimeout(connectionTimeoutMS); urlConnection.getResponseCode(); } finally { if (urlConnection != null) { urlConnection.disconnect(); } } } @Test @RequireRunOnSystemUser @EnsureHasPermission( Loading Loading
core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java +4 −4 Original line number Diff line number Diff line Loading @@ -19,10 +19,10 @@ package android.security.intrusiondetection; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.app.admin.ConnectEvent; import android.app.admin.DnsEvent; import android.app.admin.SecurityLog.SecurityEvent; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.security.Flags; Loading Loading @@ -223,13 +223,13 @@ public final class IntrusionDetectionEvent implements Parcelable { out.writeInt(mType); switch (mType) { case SECURITY_EVENT: out.writeParcelable(mSecurityEvent, flags); mSecurityEvent.writeToParcel(out, flags); break; case NETWORK_EVENT_DNS: out.writeParcelable(mNetworkEventDns, flags); mNetworkEventDns.writeToParcel(out, flags); break; case NETWORK_EVENT_CONNECT: out.writeParcelable(mNetworkEventConnect, flags); mNetworkEventConnect.writeToParcel(out, flags); break; default: throw new IllegalArgumentException("Invalid event type: " + mType); Loading
services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java +1 −1 Original line number Diff line number Diff line Loading @@ -62,7 +62,7 @@ public class DataAggregator { /** Initialize DataSources */ private void initialize() { mDataSources.add(new SecurityLogSource(mContext, this)); mDataSources.add(new NetworkLogSource(mContext, this)); mDataSources.add(new NetworkLogSource(this)); } /** Loading
services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java +1 −3 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.server.security.intrusiondetection; import android.app.admin.ConnectEvent; import android.app.admin.DnsEvent; import android.content.Context; import android.content.pm.PackageManagerInternal; import android.net.IIpConnectivityMetrics; import android.net.INetdEventCallback; Loading @@ -44,8 +43,7 @@ public class NetworkLogSource implements DataSource { private IIpConnectivityMetrics mIpConnectivityMetrics; private long mId; public NetworkLogSource(Context context, DataAggregator dataAggregator) throws SecurityException { public NetworkLogSource(DataAggregator dataAggregator) throws SecurityException { mDataAggregator = dataAggregator; mPm = LocalServices.getService(PackageManagerInternal.class); mId = 0; Loading
services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java +9 −6 Original line number Diff line number Diff line Loading @@ -19,14 +19,15 @@ package com.android.server.security.intrusiondetection; import android.Manifest.permission; import android.annotation.RequiresPermission; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.SecurityLog.SecurityEvent; import android.content.Context; import android.security.intrusiondetection.IntrusionDetectionEvent; import android.util.Slog; import com.android.server.LocalServices; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.function.Consumer; import java.util.stream.Collectors; Loading @@ -36,13 +37,13 @@ public class SecurityLogSource implements DataSource { private SecurityEventCallback mEventCallback; private DevicePolicyManager mDpm; private Executor mExecutor; private DevicePolicyManagerInternal mDpmInternal; private DataAggregator mDataAggregator; public SecurityLogSource(Context context, DataAggregator dataAggregator) { mDataAggregator = dataAggregator; mDpm = context.getSystemService(DevicePolicyManager.class); mExecutor = Executors.newSingleThreadExecutor(); mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class); mEventCallback = new SecurityEventCallback(); } Loading @@ -50,12 +51,13 @@ public class SecurityLogSource implements DataSource { @RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void enable() { enableAuditLog(); mDpm.setAuditLogEventCallback(mExecutor, mEventCallback); mDpmInternal.setInternalEventsCallback(mEventCallback); } @Override @RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void disable() { mDpmInternal.setInternalEventsCallback(null); disableAuditLog(); } Loading @@ -82,10 +84,11 @@ public class SecurityLogSource implements DataSource { @Override public void accept(List<SecurityEvent> events) { if (events.size() == 0) { if (events == null || events.size() == 0) { Slog.w(TAG, "No events received; caller may not be authorized"); return; } List<IntrusionDetectionEvent> intrusionDetectionEvents = events.stream() .filter(event -> event != null) Loading
services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java +15 −163 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.server.security.intrusiondetection; import static android.Manifest.permission.BIND_INTRUSION_DETECTION_EVENT_TRANSPORT_SERVICE; import static android.Manifest.permission.INTERNET; import static android.Manifest.permission.MANAGE_INTRUSION_DETECTION_STATE; import static android.Manifest.permission.READ_INTRUSION_DETECTION_STATE; Loading @@ -28,7 +27,6 @@ import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; Loading @@ -37,8 +35,8 @@ import static org.mockito.Mockito.verify; import android.annotation.SuppressLint; import android.app.admin.ConnectEvent; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.DnsEvent; import android.app.admin.SecurityLog; import android.app.admin.SecurityLog.SecurityEvent; import android.content.ComponentName; import android.content.Context; Loading @@ -53,37 +51,22 @@ import android.os.test.TestLooper; import android.security.intrusiondetection.IIntrusionDetectionServiceCommandCallback; import android.security.intrusiondetection.IIntrusionDetectionServiceStateCallback; import android.security.intrusiondetection.IntrusionDetectionEvent; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; import android.util.Log; import androidx.test.core.app.ApplicationProvider; import com.android.bedstead.harrier.BedsteadJUnit4; import com.android.bedstead.multiuser.annotations.RequireRunOnSystemUser; import com.android.bedstead.nene.TestApis; import com.android.bedstead.nene.devicepolicy.DeviceOwner; import com.android.bedstead.permissions.CommonPermissions; import com.android.bedstead.permissions.PermissionContext; import com.android.bedstead.permissions.annotations.EnsureHasPermission; import com.android.coretests.apps.testapp.LocalIntrusionDetectionEventTransport; import com.android.server.ServiceThread; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.security.GeneralSecurityException; 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; Loading @@ -107,7 +90,6 @@ public class IntrusionDetectionServiceTest { private static final int ERROR_DATA_SOURCE_UNAVAILABLE = IIntrusionDetectionServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE; private static DeviceOwner sDeviceOwner; private Context mContext; private IntrusionDetectionEventTransportConnection mIntrusionDetectionEventTransportConnection; Loading @@ -124,6 +106,8 @@ public class IntrusionDetectionServiceTest { "com.android.coretests.apps.testapp"; private static final String TEST_SERVICE = TEST_PKG + ".TestLoggingService"; DevicePolicyManagerInternal mDevicePolicyManagerInternal; @SuppressLint("VisibleForTests") @Before public void setUp() throws Exception { Loading Loading @@ -189,6 +173,7 @@ public class IntrusionDetectionServiceTest { } @Test @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void testAddStateCallback_Disabled_TwoStateCallbacks() throws RemoteException { StateCallback scb1 = new StateCallback(); assertEquals(STATE_UNKNOWN, scb1.mState); Loading @@ -204,7 +189,7 @@ public class IntrusionDetectionServiceTest { } @Test @Ignore("Unit test does not run as system service UID") @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void testRemoveStateCallback() throws RemoteException { mIntrusionDetectionService.setState(STATE_DISABLED); StateCallback scb1 = new StateCallback(); Loading @@ -220,15 +205,19 @@ public class IntrusionDetectionServiceTest { mIntrusionDetectionService.getBinderService().removeStateCallback(scb2); CommandCallback ccb = new CommandCallback(); // Enable will fail; caller does not run as system server. doNothing().when(mDataAggregator).enable(); mIntrusionDetectionService.getBinderService().enable(ccb); mTestLooper.dispatchAll(); assertEquals(STATE_ENABLED, scb1.mState); assertEquals(STATE_DISABLED, scb2.mState); assertNull(ccb.mErrorCode); } @Ignore("Unit test does not run as system service UID") @Test @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void testEnable_FromDisabled_TwoStateCallbacks() throws RemoteException { mIntrusionDetectionService.setState(STATE_DISABLED); StateCallback scb1 = new StateCallback(); Loading @@ -243,6 +232,9 @@ public class IntrusionDetectionServiceTest { CommandCallback ccb = new CommandCallback(); mIntrusionDetectionService.getBinderService().enable(ccb); // Enable will fail; caller does not run as system server. doNothing().when(mDataAggregator).enable(); mTestLooper.dispatchAll(); verify(mDataAggregator, times(1)).enable(); Loading Loading @@ -319,7 +311,7 @@ public class IntrusionDetectionServiceTest { assertNull(ccb.mErrorCode); } @Ignore("Enable once the IntrusionDetectionEventTransportConnection is ready") @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) @Test public void testEnable_FromDisable_TwoStateCallbacks_TransportUnavailable() throws RemoteException { Loading Loading @@ -389,146 +381,6 @@ public class IntrusionDetectionServiceTest { assertNotNull(receivedEvents.get(2).getDnsEvent()); } @Test @Ignore("Unit test does not run as system service UID") @RequireRunOnSystemUser @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void testDataAggregator_AddSecurityEvent() throws Exception { mIntrusionDetectionService.setState(STATE_ENABLED); ServiceThread mockThread = spy(ServiceThread.class); mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread); // SecurityLogging generates a number of events and callbacks, so create a latch to wait for // the given event. String eventString = this.getClass().getName() + ".testSecurityEvent"; final CountDownLatch latch = new CountDownLatch(1); // TODO: Replace this mock when the IntrusionDetectionEventTransportConnection is ready. doAnswer( new Answer<Boolean>() { @Override public Boolean answer(InvocationOnMock input) { List<IntrusionDetectionEvent> receivedEvents = (List<IntrusionDetectionEvent>) input.getArguments()[0]; for (IntrusionDetectionEvent event : receivedEvents) { if (event.getType() == IntrusionDetectionEvent.SECURITY_EVENT) { SecurityEvent securityEvent = event.getSecurityEvent(); Object[] eventData = (Object[]) securityEvent.getData(); if (securityEvent.getTag() == SecurityLog.TAG_KEY_GENERATED && eventData[1].equals(eventString)) { latch.countDown(); } } } return true; } }) .when(mIntrusionDetectionEventTransportConnection).addData(any()); mDataAggregator.enable(); // Generate the security event. generateSecurityEvent(eventString); TestApis.devicePolicy().forceSecurityLogs(); // Verify the event is received. mTestLooper.startAutoDispatch(); assertTrue(latch.await(1, TimeUnit.SECONDS)); mTestLooper.stopAutoDispatch(); mDataAggregator.disable(); } @Test @RequireRunOnSystemUser @Ignore("Unit test does not run as system service UID") @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void testDataAggregator_AddNetworkEvent() throws Exception { mIntrusionDetectionService.setState(STATE_ENABLED); ServiceThread mockThread = spy(ServiceThread.class); mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread); // Network logging may log multiple and callbacks, so create a latch to wait for // the given event. // eventServer must be a valid domain to generate a network log event. String eventServer = "google.com"; final CountDownLatch latch = new CountDownLatch(1); // TODO: Replace this mock when the IntrusionDetectionEventTransportConnection is ready. doAnswer( new Answer<Boolean>() { @Override public Boolean answer(InvocationOnMock input) { List<IntrusionDetectionEvent> receivedEvents = (List<IntrusionDetectionEvent>) input.getArguments()[0]; for (IntrusionDetectionEvent event : receivedEvents) { if (event.getType() == IntrusionDetectionEvent.NETWORK_EVENT_DNS) { DnsEvent dnsEvent = event.getDnsEvent(); if (dnsEvent.getHostname().equals(eventServer)) { latch.countDown(); } } } return true; } }) .when(mIntrusionDetectionEventTransportConnection).addData(any()); mDataAggregator.enable(); // Generate the network event. generateNetworkEvent(eventServer); TestApis.devicePolicy().forceNetworkLogs(); // Verify the event is received. mTestLooper.startAutoDispatch(); assertTrue(latch.await(1, TimeUnit.SECONDS)); mTestLooper.stopAutoDispatch(); mDataAggregator.disable(); } /** Emits a given string into security log (if enabled). */ private void generateSecurityEvent(String eventString) throws IllegalArgumentException, GeneralSecurityException, IOException { if (eventString == null || eventString.isEmpty()) { throw new IllegalArgumentException( "Error generating security event: eventString must not be empty"); } final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore"); keyGen.initialize( new KeyGenParameterSpec.Builder(eventString, KeyProperties.PURPOSE_SIGN).build()); // Emit key generation event. final KeyPair keyPair = keyGen.generateKeyPair(); assertNotNull(keyPair); final KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); ks.load(null); // Emit key destruction event. ks.deleteEntry(eventString); } /** Emits a given string into network log (if enabled). */ private void generateNetworkEvent(String server) throws IllegalArgumentException, IOException { if (server == null || server.isEmpty()) { throw new IllegalArgumentException( "Error generating network event: server must not be empty"); } HttpURLConnection urlConnection = null; int connectionTimeoutMS = 2_000; try (PermissionContext p = TestApis.permissions().withPermission(INTERNET)) { final URL url = new URL("http://" + server); urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setConnectTimeout(connectionTimeoutMS); urlConnection.setReadTimeout(connectionTimeoutMS); urlConnection.getResponseCode(); } finally { if (urlConnection != null) { urlConnection.disconnect(); } } } @Test @RequireRunOnSystemUser @EnsureHasPermission( Loading