summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Liz Prucka <lizprucka@google.com> 2024-10-29 19:25:05 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-10-29 19:25:05 +0000
commit8192775f5925c12c82d61cc01445cec1ddf2c67e (patch)
treebb13b31391bd05859f2c4f31e9eddc7e800fe23a
parentea86c734290258cb4e218172e68695aceba5a6ba (diff)
parent88b98be37bd2c07f8f96ba33b43215e98842710d (diff)
Merge "[Forensic] Added Security Logging" into main
-rw-r--r--services/core/java/com/android/server/security/forensic/DataAggregator.java11
-rw-r--r--services/core/java/com/android/server/security/forensic/ForensicService.java2
-rw-r--r--services/core/java/com/android/server/security/forensic/SecurityLogSource.java139
-rw-r--r--services/tests/security/forensic/Android.bp3
-rw-r--r--services/tests/security/forensic/AndroidManifest.xml7
-rw-r--r--services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java9
6 files changed, 162 insertions, 9 deletions
diff --git a/services/core/java/com/android/server/security/forensic/DataAggregator.java b/services/core/java/com/android/server/security/forensic/DataAggregator.java
index 0079818e733b..cc473caa0ee7 100644
--- a/services/core/java/com/android/server/security/forensic/DataAggregator.java
+++ b/services/core/java/com/android/server/security/forensic/DataAggregator.java
@@ -16,6 +16,7 @@
package com.android.server.security.forensic;
+import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -38,11 +39,14 @@ public class DataAggregator {
private final ForensicService mForensicService;
private final ArrayList<DataSource> mDataSources;
+ private Context mContext;
private List<ForensicEvent> mStoredEvents = new ArrayList<>();
private ServiceThread mHandlerThread;
private Handler mHandler;
- public DataAggregator(ForensicService forensicService) {
+
+ public DataAggregator(Context context, ForensicService forensicService) {
mForensicService = forensicService;
+ mContext = context;
mDataSources = new ArrayList<DataSource>();
}
@@ -58,6 +62,8 @@ public class DataAggregator {
*/
// TODO: Add the corresponding data sources
public boolean initialize() {
+ SecurityLogSource securityLogSource = new SecurityLogSource(mContext, this);
+ mDataSources.add(securityLogSource);
return true;
}
@@ -93,6 +99,9 @@ public class DataAggregator {
*/
public void disable() {
mHandler.obtainMessage(MSG_DISABLE).sendToTarget();
+ for (DataSource ds : mDataSources) {
+ ds.disable();
+ }
}
private void onNewSingleData(ForensicEvent event) {
diff --git a/services/core/java/com/android/server/security/forensic/ForensicService.java b/services/core/java/com/android/server/security/forensic/ForensicService.java
index 53b07c04139c..01f630b60ff5 100644
--- a/services/core/java/com/android/server/security/forensic/ForensicService.java
+++ b/services/core/java/com/android/server/security/forensic/ForensicService.java
@@ -332,7 +332,7 @@ public class ForensicService extends SystemService {
@Override
public DataAggregator getDataAggregator(ForensicService forensicService) {
- return new DataAggregator(forensicService);
+ return new DataAggregator(mContext, forensicService);
}
}
}
diff --git a/services/core/java/com/android/server/security/forensic/SecurityLogSource.java b/services/core/java/com/android/server/security/forensic/SecurityLogSource.java
new file mode 100644
index 000000000000..0f1aa42a2f46
--- /dev/null
+++ b/services/core/java/com/android/server/security/forensic/SecurityLogSource.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2024 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.server.security.forensic;
+
+import android.Manifest.permission;
+import android.annotation.RequiresPermission;
+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;
+import java.util.function.Consumer;
+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;
+ private Executor mExecutor;
+ private DataAggregator mDataAggregator;
+
+ public SecurityLogSource(Context context, DataAggregator dataAggregator) {
+ mDataAggregator = dataAggregator;
+ mDpm = context.getSystemService(DevicePolicyManager.class);
+ mExecutor = Executors.newSingleThreadExecutor();
+ mEventCallback = new SecurityEventCallback();
+ }
+
+ @Override
+ @RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
+ public void enable() {
+ enableAuditLog();
+ mDpm.setAuditLogEventCallback(mExecutor, mEventCallback);
+ }
+
+ @Override
+ @RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
+ public void disable() {
+ disableAuditLog();
+ }
+
+ @RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
+ private void enableAuditLog() {
+ if (!isAuditLogEnabled()) {
+ mDpm.setAuditLogEnabled(true);
+ }
+ }
+
+ @RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
+ private void disableAuditLog() {
+ if (isAuditLogEnabled()) {
+ mDpm.setAuditLogEnabled(false);
+ }
+ }
+
+ /**
+ * Check if security audit logging is enabled for the caller.
+ *
+ * @return Whether security audit logging is enabled.
+ */
+ public boolean isAuditLogEnabled() {
+ return mDpm.isAuditLogEnabled();
+ }
+
+ private class SecurityEventCallback implements Consumer<List<SecurityEvent>> {
+
+ @Override
+ public void accept(List<SecurityEvent> events) {
+ List<ForensicEvent> forensicEvents =
+ events.stream()
+ .filter(event -> event != null)
+ .map(event -> toForensicEvent(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/Android.bp b/services/tests/security/forensic/Android.bp
index adc49040a004..77a87afba6a7 100644
--- a/services/tests/security/forensic/Android.bp
+++ b/services/tests/security/forensic/Android.bp
@@ -24,6 +24,9 @@ android_test {
"platform-test-annotations",
"services.core",
"truth",
+ "Nene",
+ "Harrier",
+ "TestApp",
],
platform_apis: true,
diff --git a/services/tests/security/forensic/AndroidManifest.xml b/services/tests/security/forensic/AndroidManifest.xml
index 40feb19aecba..c5b3d40ce254 100644
--- a/services/tests/security/forensic/AndroidManifest.xml
+++ b/services/tests/security/forensic/AndroidManifest.xml
@@ -15,10 +15,13 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.security.forensic.tests">
+ package="com.android.server.security.forensic.tests">
+
+ <uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING" />
+ <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
<application android:testOnly="true">
- <uses-library android:name="android.test.runner"/>
+ <uses-library android:name="android.test.runner"/>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
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 feb00e760ce6..40e00344f87a 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
@@ -36,13 +36,13 @@ import android.security.forensic.IForensicServiceCommandCallback;
import android.security.forensic.IForensicServiceStateCallback;
import android.util.ArrayMap;
+import androidx.test.core.app.ApplicationProvider;
+
import com.android.server.ServiceThread;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
@@ -64,7 +64,6 @@ public class ForensicServiceTest {
private static final int ERROR_DATA_SOURCE_UNAVAILABLE =
IForensicServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE;
- @Mock
private Context mContext;
private BackupTransportConnection mBackupTransportConnection;
private DataAggregator mDataAggregator;
@@ -77,7 +76,7 @@ public class ForensicServiceTest {
@SuppressLint("VisibleForTests")
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
mTestLooper = new TestLooper();
mLooper = mTestLooper.getLooper();
@@ -491,7 +490,7 @@ public class ForensicServiceTest {
@Override
public DataAggregator getDataAggregator(ForensicService forensicService) {
- mDataAggregator = spy(new DataAggregator(forensicService));
+ mDataAggregator = spy(new DataAggregator(mContext, forensicService));
return mDataAggregator;
}
}