diff options
| author | 2024-10-29 19:25:05 +0000 | |
|---|---|---|
| committer | 2024-10-29 19:25:05 +0000 | |
| commit | 8192775f5925c12c82d61cc01445cec1ddf2c67e (patch) | |
| tree | bb13b31391bd05859f2c4f31e9eddc7e800fe23a | |
| parent | ea86c734290258cb4e218172e68695aceba5a6ba (diff) | |
| parent | 88b98be37bd2c07f8f96ba33b43215e98842710d (diff) | |
Merge "[Forensic] Added Security Logging" into main
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; } } |