diff options
3 files changed, 123 insertions, 86 deletions
diff --git a/core/java/android/security/forensic/ForensicEvent.java b/core/java/android/security/forensic/ForensicEvent.java index 90906edcc636..3d908cca150c 100644 --- a/core/java/android/security/forensic/ForensicEvent.java +++ b/core/java/android/security/forensic/ForensicEvent.java @@ -17,13 +17,17 @@ package android.security.forensic; import android.annotation.FlaggedApi; +import android.annotation.IntDef; import android.annotation.NonNull; +import android.app.admin.ConnectEvent; +import android.app.admin.DnsEvent; +import android.app.admin.SecurityLog.SecurityEvent; import android.os.Parcel; import android.os.Parcelable; import android.security.Flags; -import android.util.ArrayMap; -import java.util.Map; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * A class that represents a forensic event. @@ -33,11 +37,24 @@ import java.util.Map; public final class ForensicEvent implements Parcelable { private static final String TAG = "ForensicEvent"; - @NonNull - private final String mType; + public static final int SECURITY_EVENT = 0; + public static final int NETWORK_EVENT_DNS = 1; + public static final int NETWORK_EVENT_CONNECT = 2; - @NonNull - private final Map<String, String> mKeyValuePairs; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + ForensicEvent.SECURITY_EVENT, + ForensicEvent.NETWORK_EVENT_DNS, + ForensicEvent.NETWORK_EVENT_CONNECT, + }) + public @interface EventType {} + + @NonNull @EventType private final int mType; + + private final SecurityEvent mSecurityEvent; + private final DnsEvent mNetworkEventDns; + private final ConnectEvent mNetworkEventConnect; public static final @NonNull Parcelable.Creator<ForensicEvent> CREATOR = new Parcelable.Creator<>() { @@ -50,30 +67,99 @@ public final class ForensicEvent implements Parcelable { } }; - public ForensicEvent(@NonNull String type, @NonNull Map<String, String> keyValuePairs) { - mType = type; - mKeyValuePairs = keyValuePairs; + public ForensicEvent(@NonNull SecurityEvent securityEvent) { + mType = SECURITY_EVENT; + mSecurityEvent = securityEvent; + mNetworkEventDns = null; + mNetworkEventConnect = null; + } + + public ForensicEvent(@NonNull DnsEvent dnsEvent) { + mType = NETWORK_EVENT_DNS; + mNetworkEventDns = dnsEvent; + mSecurityEvent = null; + mNetworkEventConnect = null; + } + + public ForensicEvent(@NonNull ConnectEvent connectEvent) { + mType = NETWORK_EVENT_CONNECT; + mNetworkEventConnect = connectEvent; + mSecurityEvent = null; + mNetworkEventDns = null; } private ForensicEvent(@NonNull Parcel in) { - mType = in.readString(); - mKeyValuePairs = new ArrayMap<>(in.readInt()); - in.readMap(mKeyValuePairs, getClass().getClassLoader(), String.class, String.class); + mType = in.readInt(); + switch (mType) { + case SECURITY_EVENT: + mSecurityEvent = SecurityEvent.CREATOR.createFromParcel(in); + mNetworkEventDns = null; + mNetworkEventConnect = null; + break; + case NETWORK_EVENT_DNS: + mNetworkEventDns = DnsEvent.CREATOR.createFromParcel(in); + mSecurityEvent = null; + mNetworkEventConnect = null; + break; + case NETWORK_EVENT_CONNECT: + mNetworkEventConnect = ConnectEvent.CREATOR.createFromParcel(in); + mSecurityEvent = null; + mNetworkEventDns = null; + break; + default: + throw new IllegalArgumentException("Invalid event type: " + mType); + } } - public String getType() { + /** Returns the type of the forensic event. */ + @NonNull + public @EventType int getType() { return mType; } - public Map<String, String> getKeyValuePairs() { - return mKeyValuePairs; + /** Returns the SecurityEvent object. */ + @NonNull + public SecurityEvent getSecurityEvent() { + if (mType == SECURITY_EVENT) { + return mSecurityEvent; + } + throw new IllegalArgumentException("Event type is not security event: " + mType); + } + + /** Returns the DnsEvent object. */ + @NonNull + public DnsEvent getDnsEvent() { + if (mType == NETWORK_EVENT_DNS) { + return mNetworkEventDns; + } + throw new IllegalArgumentException("Event type is not network DNS event: " + mType); + } + + /** Returns the ConnectEvent object. */ + @NonNull + public ConnectEvent getConnectEvent() { + if (mType == NETWORK_EVENT_CONNECT) { + return mNetworkEventConnect; + } + throw new IllegalArgumentException("Event type is not network connect event: " + mType); } @Override public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeString(mType); - out.writeInt(mKeyValuePairs.size()); - out.writeMap(mKeyValuePairs); + out.writeInt(mType); + switch (mType) { + case SECURITY_EVENT: + out.writeParcelable(mSecurityEvent, flags); + break; + case NETWORK_EVENT_DNS: + out.writeParcelable(mNetworkEventDns, flags); + break; + case NETWORK_EVENT_CONNECT: + out.writeParcelable(mNetworkEventConnect, flags); + break; + default: + throw new IllegalArgumentException("Invalid event type: " + mType); + } } @FlaggedApi(Flags.FLAG_AFL_API) @@ -86,7 +172,6 @@ public final class ForensicEvent implements Parcelable { public String toString() { return "ForensicEvent{" + "mType=" + mType - + ", mKeyValuePairs=" + mKeyValuePairs + '}'; } } diff --git a/services/core/java/com/android/server/security/forensic/SecurityLogSource.java b/services/core/java/com/android/server/security/forensic/SecurityLogSource.java index 0f1aa42a2f46..e1b49c42018b 100644 --- a/services/core/java/com/android/server/security/forensic/SecurityLogSource.java +++ b/services/core/java/com/android/server/security/forensic/SecurityLogSource.java @@ -22,9 +22,7 @@ import android.app.admin.DevicePolicyManager; import android.app.admin.SecurityLog.SecurityEvent; import android.content.Context; import android.security.forensic.ForensicEvent; -import android.util.ArrayMap; -import java.util.Arrays; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -34,10 +32,6 @@ import java.util.stream.Collectors; public class SecurityLogSource implements DataSource { private static final String TAG = "Forensic SecurityLogSource"; - private static final String EVENT_TYPE = "SecurityEvent"; - private static final String EVENT_TAG = "TAG"; - private static final String EVENT_TIME = "TIME"; - private static final String EVENT_DATA = "DATA"; private SecurityEventCallback mEventCallback = new SecurityEventCallback(); private DevicePolicyManager mDpm; @@ -94,46 +88,9 @@ public class SecurityLogSource implements DataSource { List<ForensicEvent> forensicEvents = events.stream() .filter(event -> event != null) - .map(event -> toForensicEvent(event)) + .map(event -> new ForensicEvent(event)) .collect(Collectors.toList()); mDataAggregator.addBatchData(forensicEvents); } - - private ForensicEvent toForensicEvent(SecurityEvent event) { - ArrayMap<String, String> keyValuePairs = new ArrayMap<>(); - keyValuePairs.put(EVENT_TIME, String.valueOf(event.getTimeNanos())); - // TODO: Map tag to corresponding string - keyValuePairs.put(EVENT_TAG, String.valueOf(event.getTag())); - keyValuePairs.put(EVENT_DATA, eventDataToString(event.getData())); - return new ForensicEvent(EVENT_TYPE, keyValuePairs); - } - - /** - * Convert event data to a String. - * - * @param obj Object containing an Integer, Long, Float, String, null, or Object[] of the - * same. - * @return String representation of event data. - */ - private String eventDataToString(Object obj) { - if (obj == null) { - return ""; - } else if (obj instanceof Integer - || obj instanceof Long - || obj instanceof Float - || obj instanceof String) { - return String.valueOf(obj); - } else if (obj instanceof Object[]) { - Object[] objArray = (Object[]) obj; - String[] strArray = new String[objArray.length]; - for (int i = 0; i < objArray.length; ++i) { - strArray[i] = eventDataToString(objArray[i]); - } - return Arrays.toString((String[]) strArray); - } else { - throw new IllegalArgumentException( - "Unsupported data type: " + obj.getClass().getSimpleName()); - } - } } } diff --git a/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java b/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java index 0da6db634330..03c449cc8d69 100644 --- a/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java +++ b/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java @@ -31,6 +31,9 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.annotation.SuppressLint; +import android.app.admin.ConnectEvent; +import android.app.admin.DnsEvent; +import android.app.admin.SecurityLog.SecurityEvent; import android.content.Context; import android.os.Looper; import android.os.PermissionEnforcer; @@ -40,7 +43,6 @@ import android.os.test.TestLooper; import android.security.forensic.ForensicEvent; import android.security.forensic.IForensicServiceCommandCallback; import android.security.forensic.IForensicServiceStateCallback; -import android.util.ArrayMap; import androidx.test.core.app.ApplicationProvider; @@ -53,7 +55,6 @@ import org.mockito.ArgumentCaptor; import java.util.ArrayList; import java.util.List; -import java.util.Map; public class ForensicServiceTest { private static final int STATE_UNKNOWN = IForensicServiceStateCallback.State.UNKNOWN; @@ -300,23 +301,19 @@ public class ForensicServiceTest { ServiceThread mockThread = spy(ServiceThread.class); mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread); - String eventOneType = "event_one_type"; - String eventOneMapKey = "event_one_map_key"; - String eventOneMapVal = "event_one_map_val"; - Map<String, String> eventOneMap = new ArrayMap<String, String>(); - eventOneMap.put(eventOneMapKey, eventOneMapVal); - ForensicEvent eventOne = new ForensicEvent(eventOneType, eventOneMap); + SecurityEvent securityEvent = new SecurityEvent(0, new byte[0]); + ForensicEvent eventOne = new ForensicEvent(securityEvent); - String eventTwoType = "event_two_type"; - String eventTwoMapKey = "event_two_map_key"; - String eventTwoMapVal = "event_two_map_val"; - Map<String, String> eventTwoMap = new ArrayMap<String, String>(); - eventTwoMap.put(eventTwoMapKey, eventTwoMapVal); - ForensicEvent eventTwo = new ForensicEvent(eventTwoType, eventTwoMap); + ConnectEvent connectEvent = new ConnectEvent("127.0.0.1", 80, null, 0); + ForensicEvent eventTwo = new ForensicEvent(connectEvent); + + DnsEvent dnsEvent = new DnsEvent(null, new String[] {"127.0.0.1"}, 1, null, 0); + ForensicEvent eventThree = new ForensicEvent(dnsEvent); List<ForensicEvent> events = new ArrayList<>(); events.add(eventOne); events.add(eventTwo); + events.add(eventThree); doReturn(true).when(mForensicEventTransportConnection).addData(any()); @@ -327,18 +324,16 @@ public class ForensicServiceTest { ArgumentCaptor<List<ForensicEvent>> captor = ArgumentCaptor.forClass(List.class); verify(mForensicEventTransportConnection).addData(captor.capture()); List<ForensicEvent> receivedEvents = captor.getValue(); - assertEquals(receivedEvents.size(), 2); + assertEquals(receivedEvents.size(), 3); - assertEquals(receivedEvents.getFirst().getType(), eventOneType); - assertEquals(receivedEvents.getFirst().getKeyValuePairs().size(), 1); - assertEquals(receivedEvents.getFirst().getKeyValuePairs().get(eventOneMapKey), - eventOneMapVal); + assertEquals(receivedEvents.get(0).getType(), ForensicEvent.SECURITY_EVENT); + assertNotNull(receivedEvents.get(0).getSecurityEvent()); - assertEquals(receivedEvents.getLast().getType(), eventTwoType); - assertEquals(receivedEvents.getLast().getKeyValuePairs().size(), 1); - assertEquals(receivedEvents.getLast().getKeyValuePairs().get(eventTwoMapKey), - eventTwoMapVal); + assertEquals(receivedEvents.get(1).getType(), ForensicEvent.NETWORK_EVENT_CONNECT); + assertNotNull(receivedEvents.get(1).getConnectEvent()); + assertEquals(receivedEvents.get(2).getType(), ForensicEvent.NETWORK_EVENT_DNS); + assertNotNull(receivedEvents.get(2).getDnsEvent()); } private class MockInjector implements ForensicService.Injector { |