Merge "Log additional events in security log."
diff --git a/api/current.txt b/api/current.txt
index ec3c9d3..de3be1f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6724,20 +6724,46 @@
public class SecurityLog {
ctor public SecurityLog();
+ field public static final int LEVEL_ERROR = 3; // 0x3
+ field public static final int LEVEL_INFO = 1; // 0x1
+ field public static final int LEVEL_WARNING = 2; // 0x2
field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
+ field public static final int TAG_CERT_AUTHORITY_INSTALLED = 210029; // 0x3346d
+ field public static final int TAG_CERT_AUTHORITY_REMOVED = 210030; // 0x3346e
+ field public static final int TAG_KEYGUARD_DISABLED_FEATURES_SET = 210021; // 0x33465
field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
+ field public static final int TAG_KEY_DESTRUCTION = 210026; // 0x3346a
+ field public static final int TAG_KEY_GENERATED = 210024; // 0x33468
+ field public static final int TAG_KEY_IMPORT = 210025; // 0x33469
+ field public static final int TAG_LOGGING_STARTED = 210011; // 0x3345b
+ field public static final int TAG_LOGGING_STOPPED = 210012; // 0x3345c
+ field public static final int TAG_LOG_BUFFER_SIZE_CRITICAL = 210015; // 0x3345f
+ field public static final int TAG_MAX_PASSWORD_ATTEMPTS_SET = 210020; // 0x33464
+ field public static final int TAG_MAX_SCREEN_LOCK_TIMEOUT_SET = 210019; // 0x33463
+ field public static final int TAG_MEDIA_MOUNT = 210013; // 0x3345d
+ field public static final int TAG_MEDIA_UNMOUNT = 210014; // 0x3345e
+ field public static final int TAG_OS_SHUTDOWN = 210010; // 0x3345a
+ field public static final int TAG_OS_STARTUP = 210009; // 0x33459
+ field public static final int TAG_PASSWORD_COMPLEXITY_SET = 210017; // 0x33461
+ field public static final int TAG_PASSWORD_EXPIRATION_SET = 210016; // 0x33460
+ field public static final int TAG_PASSWORD_HISTORY_LENGTH_SET = 210018; // 0x33462
+ field public static final int TAG_REMOTE_LOCK = 210022; // 0x33466
field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
+ field public static final int TAG_USER_RESTRICTION_ADDED = 210027; // 0x3346b
+ field public static final int TAG_USER_RESTRICTION_REMOVED = 210028; // 0x3346c
+ field public static final int TAG_WIPE_FAILURE = 210023; // 0x33467
}
public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
method public int describeContents();
method public java.lang.Object getData();
method public long getId();
+ method public int getLogLevel();
method public int getTag();
method public long getTimeNanos();
method public void writeToParcel(android.os.Parcel, int);
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index d3b66d0..08effd9 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.TestApi;
+import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemProperties;
@@ -53,64 +54,367 @@
TAG_APP_PROCESS_START,
TAG_KEYGUARD_DISMISSED,
TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT,
- TAG_KEYGUARD_SECURED
+ TAG_KEYGUARD_SECURED,
+ TAG_OS_STARTUP,
+ TAG_OS_SHUTDOWN,
+ TAG_LOGGING_STARTED,
+ TAG_LOGGING_STOPPED,
+ TAG_MEDIA_MOUNT,
+ TAG_MEDIA_UNMOUNT,
+ TAG_LOG_BUFFER_SIZE_CRITICAL,
+ TAG_PASSWORD_EXPIRATION_SET,
+ TAG_PASSWORD_COMPLEXITY_SET,
+ TAG_PASSWORD_HISTORY_LENGTH_SET,
+ TAG_MAX_SCREEN_LOCK_TIMEOUT_SET,
+ TAG_MAX_PASSWORD_ATTEMPTS_SET,
+ TAG_KEYGUARD_DISABLED_FEATURES_SET,
+ TAG_REMOTE_LOCK,
+ TAG_USER_RESTRICTION_ADDED,
+ TAG_USER_RESTRICTION_REMOVED,
+ TAG_WIPE_FAILURE,
+ TAG_KEY_GENERATED,
+ TAG_KEY_IMPORT,
+ TAG_KEY_DESTRUCTION,
+ TAG_CERT_AUTHORITY_INSTALLED,
+ TAG_CERT_AUTHORITY_REMOVED,
})
public @interface SecurityLogTag {}
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "LEVEL_" }, value = {
+ LEVEL_INFO,
+ LEVEL_WARNING,
+ LEVEL_ERROR
+ })
+ public @interface SecurityLogLevel {}
+
/**
- * Indicate that an ADB interactive shell was opened via "adb shell".
+ * Indicates that an ADB interactive shell was opened via "adb shell".
* There is no extra payload in the log event.
*/
public static final int TAG_ADB_SHELL_INTERACTIVE =
SecurityLogTags.SECURITY_ADB_SHELL_INTERACTIVE;
+
/**
- * Indicate that an shell command was issued over ADB via "adb shell command"
- * The log entry contains a string data of the shell command, accessible via
- * {@link SecurityEvent#getData()}
+ * Indicates that a shell command was issued over ADB via {@code adb shell <command>}
+ * The log entry contains a {@code String} payload containing the shell command, accessible
+ * via {@link SecurityEvent#getData()}.
*/
public static final int TAG_ADB_SHELL_CMD = SecurityLogTags.SECURITY_ADB_SHELL_COMMAND;
+
/**
- * Indicate that a file was pulled from the device via the adb daemon, for example via
- * "adb pull". The log entry contains a string data of the path of the pulled file,
- * accessible via {@link SecurityEvent#getData()}
+ * Indicates that a file was pulled from the device via the adb daemon, for example via
+ * {@code adb pull}. The log entry contains a {@code String} payload containing the path of the
+ * pulled file on the device, accessible via {@link SecurityEvent#getData()}.
*/
public static final int TAG_SYNC_RECV_FILE = SecurityLogTags.SECURITY_ADB_SYNC_RECV;
+
/**
- * Indicate that a file was pushed to the device via the adb daemon, for example via
- * "adb push". The log entry contains a string data of the destination path of the
- * pushed file, accessible via {@link SecurityEvent#getData()}
+ * Indicates that a file was pushed to the device via the adb daemon, for example via
+ * {@code adb push}. The log entry contains a {@code String} payload containing the destination
+ * path of the pushed file, accessible via {@link SecurityEvent#getData()}.
*/
public static final int TAG_SYNC_SEND_FILE = SecurityLogTags.SECURITY_ADB_SYNC_SEND;
+
/**
- * Indicate that an app process was started. The log entry contains the following
+ * Indicates that an app process was started. The log entry contains the following
* information about the process encapsulated in an {@link Object} array, accessible via
* {@link SecurityEvent#getData()}:
- * process name (String), exact start time (long), app Uid (integer), app Pid (integer),
- * seinfo tag (String), SHA-256 hash of the base APK in hexadecimal (String)
+ * <li> [0] process name ({@code String})
+ * <li> [1] exact start time in milliseconds according to {@code System.currentTimeMillis()}
+ * ({@code Long})
+ * <li> [2] app uid ({@code Integer})
+ * <li> [3] app pid ({@code Integer})
+ * <li> [4] seinfo tag ({@code String})
+ * <li> [5] SHA-256 hash of the base APK in hexadecimal ({@code String})
*/
public static final int TAG_APP_PROCESS_START = SecurityLogTags.SECURITY_APP_PROCESS_START;
+
/**
- * Indicate that keyguard is being dismissed.
+ * Indicates that keyguard has been dismissed.
* There is no extra payload in the log event.
*/
- public static final int TAG_KEYGUARD_DISMISSED =
- SecurityLogTags.SECURITY_KEYGUARD_DISMISSED;
+ public static final int TAG_KEYGUARD_DISMISSED = SecurityLogTags.SECURITY_KEYGUARD_DISMISSED;
+
/**
- * Indicate that there has been an authentication attempt to dismiss the keyguard. The log entry
- * contains the following information about the attempt encapsulated in an {@link Object} array,
- * accessible via {@link SecurityEvent#getData()}:
- * attempt result (integer, 1 for successful, 0 for unsuccessful), strength of auth method
- * (integer, 1 if strong auth method was used, 0 otherwise)
+ * Indicates that there has been an authentication attempt to dismiss the keyguard. The log
+ * entry contains the following information about the attempt encapsulated in an {@link Object}
+ * array, accessible via {@link SecurityEvent#getData()}:
+ * <li> [0] attempt result ({@code Integer}, 1 for successful, 0 for unsuccessful)
+ * <li> [1] strength of authentication method ({@code Integer}, 1 if strong authentication
+ * method was used, 0 otherwise)
*/
public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT =
SecurityLogTags.SECURITY_KEYGUARD_DISMISS_AUTH_ATTEMPT;
+
/**
- * Indicate that the device has been locked, either by user or by timeout.
- * There is no extra payload in the log event.
+ * Indicates that the device has been locked, either by the user or by a timeout. There is no
+ * extra payload in the log event.
*/
public static final int TAG_KEYGUARD_SECURED = SecurityLogTags.SECURITY_KEYGUARD_SECURED;
/**
+ * Indicates that the Android OS has started. The log entry contains the following information
+ * about the startup time software integrity check encapsulated in an {@link Object} array,
+ * accessible via {@link SecurityEvent#getData()}:
+ * <li> [0] Verified Boot state ({@code String})
+ * <li> [1] dm-verity mode ({@code String}).
+ * <p>Verified Boot state can be one of the following:
+ * <li> {@code green} indicates that there is a full chain of trust extending from the
+ * bootloader to verified partitions including the bootloader, boot partition, and all verified
+ * partitions.
+ * <li> {@code yellow} indicates that the boot partition has been verified using the embedded
+ * certificate and the signature is valid.
+ * <li> {@code orange} indicates that the device may be freely modified. Device integrity is
+ * left to the user to verify out-of-band.
+ * <p>dm-verity mode can be one of the following:
+ * <li> {@code enforcing} indicates that the device will be restarted when corruption is
+ * detected.
+ * <li> {@code eio} indicates that an I/O error will be returned for an attempt to read
+ * corrupted data blocks.
+ * For details see Verified Boot documentation.
+ */
+ public static final int TAG_OS_STARTUP = SecurityLogTags.SECURITY_OS_STARTUP;
+
+ /**
+ * Indicates that the Android OS has shutdown. There is no extra payload in the log event.
+ */
+ public static final int TAG_OS_SHUTDOWN = SecurityLogTags.SECURITY_OS_SHUTDOWN;
+
+ /**
+ * Indicates start-up of audit logging. There is no extra payload in the log event.
+ */
+ public static final int TAG_LOGGING_STARTED = SecurityLogTags.SECURITY_LOGGING_STARTED;
+
+ /**
+ * Indicates shutdown of audit logging. There is no extra payload in the log event.
+ */
+ public static final int TAG_LOGGING_STOPPED = SecurityLogTags.SECURITY_LOGGING_STOPPED;
+
+ /**
+ * Indicates that removable media has been mounted on the device. The log entry contains the
+ * following information about the event, encapsulated in an {@link Object} array and
+ * accessible via {@link SecurityEvent#getData()}:
+ * <li> [0] mount point ({@code String})
+ * <li> [1] volume label ({@code String}).
+ */
+ public static final int TAG_MEDIA_MOUNT = SecurityLogTags.SECURITY_MEDIA_MOUNTED;
+
+ /**
+ * Indicates that removable media was unmounted from the device. The log entry contains the
+ * following information about the event, encapsulated in an {@link Object} array and
+ * accessible via {@link SecurityEvent#getData()}:
+ * <li> [0] mount point ({@code String})
+ * <li> [1] volume label ({@code String}).
+ */
+ public static final int TAG_MEDIA_UNMOUNT = SecurityLogTags.SECURITY_MEDIA_UNMOUNTED;
+
+ /**
+ * Indicates that the audit log buffer has reached 90% of its capacity. There is no extra
+ * payload in the log event.
+ */
+ public static final int TAG_LOG_BUFFER_SIZE_CRITICAL =
+ SecurityLogTags.SECURITY_LOG_BUFFER_SIZE_CRITICAL;
+
+ /**
+ * Indicates that an admin has set a password expiration timeout. The log entry contains the
+ * following information about the event, encapsulated in an {@link Object} array and accessible
+ * via {@link SecurityEvent#getData()}:
+ * <li> [0] admin package name ({@code String})
+ * <li> [1] admin user ID ({@code Integer})
+ * <li> [2] target user ID ({@code Integer})
+ * <li> [3] new password expiration timeout in milliseconds ({@code Long}).
+ * @see DevicePolicyManager#setPasswordExpirationTimeout(ComponentName, long)
+ */
+ public static final int TAG_PASSWORD_EXPIRATION_SET =
+ SecurityLogTags.SECURITY_PASSWORD_EXPIRATION_SET;
+
+ /**
+ * Indicates that an admin has set a requirement for password complexity. The log entry contains
+ * the following information about the event, encapsulated in an {@link Object} array and
+ * accessible via {@link SecurityEvent#getData()}:
+ * <li> [0] admin package name ({@code String})
+ * <li> [1] admin user ID ({@code Integer})
+ * <li> [2] target user ID ({@code Integer})
+ * <li> [3] minimum password length ({@code Integer})
+ * <li> [4] password quality constraint ({@code Integer})
+ * <li> [5] minimum number of letters ({@code Integer})
+ * <li> [6] minimum number of non-letters ({@code Integer})
+ * <li> [7] minimum number of digits ({@code Integer})
+ * <li> [8] minimum number of uppercase letters ({@code Integer})
+ * <li> [9] minimum number of lowercase letters ({@code Integer})
+ * <li> [10] minimum number of symbols ({@code Integer})
+ *
+ * @see DevicePolicyManager#setPasswordMinimumLength(ComponentName, int)
+ * @see DevicePolicyManager#setPasswordQuality(ComponentName, int)
+ * @see DevicePolicyManager#setPasswordMinimumLetters(ComponentName, int)
+ * @see DevicePolicyManager#setPasswordMinimumNonLetter(ComponentName, int)
+ * @see DevicePolicyManager#setPasswordMinimumLowerCase(ComponentName, int)
+ * @see DevicePolicyManager#setPasswordMinimumUpperCase(ComponentName, int)
+ * @see DevicePolicyManager#setPasswordMinimumNumeric(ComponentName, int)
+ * @see DevicePolicyManager#setPasswordMinimumSymbols(ComponentName, int)
+ */
+ public static final int TAG_PASSWORD_COMPLEXITY_SET =
+ SecurityLogTags.SECURITY_PASSWORD_COMPLEXITY_SET;
+
+ /**
+ * Indicates that an admin has set a password history length. The log entry contains the
+ * following information about the event encapsulated in an {@link Object} array, accessible
+ * via {@link SecurityEvent#getData()}:
+ * <li> [0] admin package name ({@code String})
+ * <li> [1] admin user ID ({@code Integer})
+ * <li> [2] target user ID ({@code Integer})
+ * <li> [3] new password history length value ({@code Integer})
+ * @see DevicePolicyManager#setPasswordHistoryLength(ComponentName, int)
+ */
+ public static final int TAG_PASSWORD_HISTORY_LENGTH_SET =
+ SecurityLogTags.SECURITY_PASSWORD_HISTORY_LENGTH_SET;
+
+ /**
+ * Indicates that an admin has set a maximum screen lock timeout. The log entry contains the
+ * following information about the event encapsulated in an {@link Object} array, accessible
+ * via {@link SecurityEvent#getData()}:
+ * <li> [0] admin package name ({@code String})
+ * <li> [1] admin user ID ({@code Integer})
+ * <li> [2] target user ID ({@code Integer})
+ * <li> [3] new screen lock timeout in milliseconds ({@code Long})
+ * @see DevicePolicyManager#setMaximumTimeToLock(ComponentName, long)
+ */
+ public static final int TAG_MAX_SCREEN_LOCK_TIMEOUT_SET =
+ SecurityLogTags.SECURITY_MAX_SCREEN_LOCK_TIMEOUT_SET;
+
+ /**
+ * Indicates that an admin has set a maximum number of failed password attempts before wiping
+ * data. The log entry contains the following information about the event encapsulated in an
+ * {@link Object} array, accessible via {@link SecurityEvent#getData()}:
+ * <li> [0] admin package name ({@code String})
+ * <li> [1] admin user ID ({@code Integer})
+ * <li> [2] target user ID ({@code Integer})
+ * <li> [3] new maximum number of failed password attempts ({@code Integer})
+ * @see DevicePolicyManager#setMaximumTimeToLock(ComponentName, long)
+ */
+ public static final int TAG_MAX_PASSWORD_ATTEMPTS_SET =
+ SecurityLogTags.SECURITY_MAX_PASSWORD_ATTEMPTS_SET;
+
+ /**
+ * Indicates that an admin has set disabled keyguard features. The log entry contains the
+ * following information about the event encapsulated in an {@link Object} array, accessible via
+ * {@link SecurityEvent#getData()}:
+ * <li> [0] admin package name ({@code String})
+ * <li> [1] admin user ID ({@code Integer})
+ * <li> [2] target user ID ({@code Integer})
+ * <li> [3] disabled keyguard feature mask ({@code Integer}).
+ * @see DevicePolicyManager#setKeyguardDisabledFeatures(ComponentName, int)
+ */
+ public static final int TAG_KEYGUARD_DISABLED_FEATURES_SET =
+ SecurityLogTags.SECURITY_KEYGUARD_DISABLED_FEATURES_SET;
+
+ /**
+ * Indicates that an admin remotely locked the device or profile. The log entry contains the
+ * following information about the event encapsulated in an {@link Object} array, accessible via
+ * {@link SecurityEvent#getData()}:
+ * <li> [0] admin package name ({@code String}),
+ * <li> [1] admin user ID ({@code Integer}).
+ */
+ public static final int TAG_REMOTE_LOCK = SecurityLogTags.SECURITY_REMOTE_LOCK;
+
+ /**
+ * Indicates a failure to wipe device or user data. There is no extra payload in the log event.
+ */
+ public static final int TAG_WIPE_FAILURE = SecurityLogTags.SECURITY_WIPE_FAILED;
+
+ /**
+ * Indicates that an authentication key was generated. The log entry contains the following
+ * information about the event, encapsulated in an {@link Object} array and accessible via
+ * {@link SecurityEvent#getData()}:
+ * <li> [0] result ({@code Integer}, 0 if operation failed, 1 if succeeded)
+ * <li> [1] alias of the key ({@code String})
+ * <li> [2] requesting process uid ({@code Integer}).
+ */
+ public static final int TAG_KEY_GENERATED =
+ SecurityLogTags.SECURITY_KEY_GENERATED;
+
+ /**
+ * Indicates that a cryptographic key was imported. The log entry contains the following
+ * information about the event, encapsulated in an {@link Object} array and accessible via
+ * {@link SecurityEvent#getData()}:
+ * <li> [0] result ({@code Integer}, 0 if operation failed, 1 if succeeded)
+ * <li> [1] alias of the key ({@code String})
+ * <li> [2] requesting process uid ({@code Integer}).
+ */
+ public static final int TAG_KEY_IMPORT = SecurityLogTags.SECURITY_KEY_IMPORTED;
+
+ /**
+ * Indicates that a cryptographic key was destroyed. The log entry contains the following
+ * information about the event, encapsulated in an {@link Object} array and accessible via
+ * {@link SecurityEvent#getData()}:
+ * <li> [0] result ({@code Integer}, 0 if operation failed, 1 if succeeded)
+ * <li> [1] alias of the key ({@code String})
+ * <li> [2] requesting process uid ({@code Integer}).
+ */
+ public static final int TAG_KEY_DESTRUCTION = SecurityLogTags.SECURITY_KEY_DESTROYED;
+
+ /**
+ * Indicates that a new root certificate has been installed into system's trusted credential
+ * storage. The log entry contains the following information about the event, encapsulated in an
+ * {@link Object} array and accessible via {@link SecurityEvent#getData()}:
+ * <li> [0] result ({@code Integer}, 0 if operation failed, 1 if succeeded)
+ * <li> [1] subject of the certificate ({@code String}).
+ */
+ public static final int TAG_CERT_AUTHORITY_INSTALLED =
+ SecurityLogTags.SECURITY_CERT_AUTHORITY_INSTALLED;
+
+ /**
+ * Indicates that a new oot certificate has been removed from system's trusted credential
+ * storage. The log entry contains the following information about the event, encapsulated in an
+ * {@link Object} array and accessible via {@link SecurityEvent#getData()}:
+ * <li> [0] result ({@code Integer}, 0 if operation failed, 1 if succeeded)
+ * <li> [1] subject of the certificate ({@code String}).
+ */
+ public static final int TAG_CERT_AUTHORITY_REMOVED =
+ SecurityLogTags.SECURITY_CERT_AUTHORITY_REMOVED;
+
+ /**
+ * Indicates that an admin has set a user restriction. The log entry contains the following
+ * information about the event, encapsulated in an {@link Object} array and accessible via
+ * {@link SecurityEvent#getData()}:
+ * <li> [0] admin package name ({@code String})
+ * <li> [1] admin user ID ({@code Integer})
+ * <li> [2] user restriction ({@code String})
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ */
+ public static final int TAG_USER_RESTRICTION_ADDED =
+ SecurityLogTags.SECURITY_USER_RESTRICTION_ADDED;
+
+ /**
+ * Indicates that an admin has removed a user restriction. The log entry contains the following
+ * information about the event, encapsulated in an {@link Object} array and accessible via
+ * {@link SecurityEvent#getData()}:
+ * <li> [0] admin package name ({@code String})
+ * <li> [1] admin user ID ({@code Integer})
+ * <li> [2] user restriction ({@code String})
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ */
+ public static final int TAG_USER_RESTRICTION_REMOVED =
+ SecurityLogTags.SECURITY_USER_RESTRICTION_REMOVED;
+
+ /**
+ * Event severity level indicating that the event corresponds to normal workflow.
+ */
+ public static final int LEVEL_INFO = 1;
+
+ /**
+ * Event severity level indicating that the event may require admin attention.
+ */
+ public static final int LEVEL_WARNING = 2;
+
+ /**
+ * Event severity level indicating that the event requires urgent admin action.
+ */
+ public static final int LEVEL_ERROR = 3;
+
+ /**
* Returns if security logging is enabled. Log producers should only write new logs if this is
* true. Under the hood this is the logical AND of whether device owner exists and whether
* it enables logging by setting the system property {@link #PROPERTY_LOGGING_ENABLED}.
@@ -198,6 +502,60 @@
return mId;
}
+ /**
+ * Returns severity level for the event.
+ */
+ public @SecurityLogLevel int getLogLevel() {
+ switch (mEvent.getTag()) {
+ case TAG_ADB_SHELL_INTERACTIVE:
+ case TAG_ADB_SHELL_CMD:
+ case TAG_SYNC_RECV_FILE:
+ case TAG_SYNC_SEND_FILE:
+ case TAG_APP_PROCESS_START:
+ case TAG_KEYGUARD_DISMISSED:
+ case TAG_KEYGUARD_SECURED:
+ case TAG_OS_STARTUP:
+ case TAG_OS_SHUTDOWN:
+ case TAG_LOGGING_STARTED:
+ case TAG_LOGGING_STOPPED:
+ case TAG_MEDIA_MOUNT:
+ case TAG_MEDIA_UNMOUNT:
+ case TAG_PASSWORD_EXPIRATION_SET:
+ case TAG_PASSWORD_COMPLEXITY_SET:
+ case TAG_PASSWORD_HISTORY_LENGTH_SET:
+ case TAG_MAX_SCREEN_LOCK_TIMEOUT_SET:
+ case TAG_MAX_PASSWORD_ATTEMPTS_SET:
+ case TAG_USER_RESTRICTION_ADDED:
+ case TAG_USER_RESTRICTION_REMOVED:
+ return LEVEL_INFO;
+ case TAG_CERT_AUTHORITY_REMOVED:
+ return getSuccess() ? LEVEL_INFO : LEVEL_ERROR;
+ case TAG_CERT_AUTHORITY_INSTALLED:
+ case TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT:
+ case TAG_KEY_IMPORT:
+ case TAG_KEY_DESTRUCTION:
+ case TAG_KEY_GENERATED:
+ return getSuccess() ? LEVEL_INFO : LEVEL_WARNING;
+ case TAG_LOG_BUFFER_SIZE_CRITICAL:
+ case TAG_WIPE_FAILURE:
+ return LEVEL_ERROR;
+ default:
+ return LEVEL_INFO;
+ }
+ }
+
+ // Success/failure if present is encoded as an integer in the first (0th) element of data.
+ private boolean getSuccess() {
+ final Object data = getData();
+ if (data == null || !(data instanceof Object[])) {
+ return false;
+ }
+
+ final Object[] array = (Object[]) data;
+ return array.length >= 1 && array[0] instanceof Integer && (Integer) array[0] != 0;
+ }
+
+
@Override
public int describeContents() {
return 0;
@@ -263,8 +621,8 @@
throws IOException;
/**
- * Retrieve all security logs whose timestamp (in nanosceonds) is equal to or greater than the
- * given timestamp. This method will block until either the last log earlier than the given
+ * Retrieve all security logs whose timestamp is equal to or greater than the given timestamp in
+ * nanoseconds. This method will block until either the last log earlier than the given
* timestamp is about to be pruned, or after a 2-hour timeout has passed.
* @hide
*/
diff --git a/core/java/android/app/admin/SecurityLogTags.logtags b/core/java/android/app/admin/SecurityLogTags.logtags
index 39371c7..be62678 100644
--- a/core/java/android/app/admin/SecurityLogTags.logtags
+++ b/core/java/android/app/admin/SecurityLogTags.logtags
@@ -10,3 +10,28 @@
210006 security_keyguard_dismissed
210007 security_keyguard_dismiss_auth_attempt (success|1),(method_strength|1)
210008 security_keyguard_secured
+
+# Additional event types for NIAP MDFPP 3.1 compliant audit logging.
+
+210009 security_os_startup (boot_state|3),(verity_mode|3)
+210010 security_os_shutdown
+210011 security_logging_started
+210012 security_logging_stopped
+210013 security_media_mounted (path|3),(label|3)
+210014 security_media_unmounted (path|3),(label|3)
+210015 security_log_buffer_size_critical
+210016 security_password_expiration_set (package|3),(admin_user|1),(target_user|1),(timeout|2|3)
+210017 security_password_complexity_set (package|3),(admin_user|1),(target_user|1),(length|1),(quality|1),(num_letters|1),(num_non_letters|1),(num_numeric|1),(num_uppercase|1),(num_lowercase|1),(num_symbols|1)
+210018 security_password_history_length_set (package|3),(admin_user|1),(target_user|1),(length|1)
+210019 security_max_screen_lock_timeout_set (package|3),(admin_user|1),(target_user|1),(timeout|2|3)
+210020 security_max_password_attempts_set (package|3),(admin_user|1),(target_user|1),(num_failures|1)
+210021 security_keyguard_disabled_features_set (package|3),(admin_user|1),(target_user|1),(features|1)
+210022 security_remote_lock (package|3),(admin_user|1),(target_user|1)
+210023 security_wipe_failed (package|3),(admin_user|1)
+210024 security_key_generated (success|1),(key_id|3),(uid|1)
+210025 security_key_imported (success|1),(key_id|3),(uid|1)
+210026 security_key_destroyed (success|1),(key_id|3),(uid|1)
+210027 security_user_restriction_added (package|3),(admin_user|1),(restriction|3)
+210028 security_user_restriction_removed (package|3),(admin_user|1),(restriction|3)
+210029 security_cert_authority_installed (success|1),(subject|3)
+210030 security_cert_authority_removed (success|1),(subject|3)
\ No newline at end of file
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 8ec4ef6..84b93e3 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -36,6 +36,7 @@
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.KeyguardManager;
+import android.app.admin.SecurityLog;
import android.app.usage.StorageStatsManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -50,7 +51,6 @@
import android.content.res.Configuration;
import android.content.res.ObbInfo;
import android.database.ContentObserver;
-import android.net.TrafficStats;
import android.net.Uri;
import android.os.Binder;
import android.os.DropBoxManager;
@@ -150,7 +150,6 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
-import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -1275,6 +1274,29 @@
mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
OBB_FLUSH_MOUNT_STATE, vol.path));
}
+ maybeLogMediaMount(vol, newState);
+ }
+
+ private void maybeLogMediaMount(VolumeInfo vol, int newState) {
+ if (!SecurityLog.isLoggingEnabled()) {
+ return;
+ }
+
+ final DiskInfo disk = vol.getDisk();
+ if (disk == null || (disk.flags & (DiskInfo.FLAG_SD | DiskInfo.FLAG_USB)) == 0) {
+ return;
+ }
+
+ // Sometimes there is a newline character.
+ final String label = disk.label != null ? disk.label.trim() : "";
+
+ if (newState == VolumeInfo.STATE_MOUNTED
+ || newState == VolumeInfo.STATE_MOUNTED_READ_ONLY) {
+ SecurityLog.writeEvent(SecurityLog.TAG_MEDIA_MOUNT, vol.path, label);
+ } else if (newState == VolumeInfo.STATE_UNMOUNTED
+ || newState == VolumeInfo.STATE_BAD_REMOVAL) {
+ SecurityLog.writeEvent(SecurityLog.TAG_MEDIA_UNMOUNT, vol.path, label);
+ }
}
private void onMoveStatusLocked(int status) {
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index b986e04..eed3102 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -21,6 +21,7 @@
import android.app.Dialog;
import android.app.IActivityManager;
import android.app.ProgressDialog;
+import android.app.admin.SecurityLog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@@ -390,6 +391,10 @@
}
}
+ if (SecurityLog.isLoggingEnabled()) {
+ SecurityLog.writeEvent(SecurityLog.TAG_OS_SHUTDOWN);
+ }
+
// start the thread that initiates shutdown
sInstance.mHandler = new Handler() {
};
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 918a355..0589790 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3313,6 +3313,7 @@
cleanUpOldUsers();
maybeSetDefaultProfileOwnerUserRestrictions();
handleStartUser(UserHandle.USER_SYSTEM);
+ maybeLogStart();
// Register an observer for watching for user setup complete and settings changes.
mSetupContentObserver.register();
@@ -3368,6 +3369,16 @@
updateSystemUpdateFreezePeriodsRecord(/* saveIfChanged */ true);
}
+ private void maybeLogStart() {
+ if (!SecurityLog.isLoggingEnabled()) {
+ return;
+ }
+ final String verifiedBootState =
+ mInjector.systemPropertiesGet("ro.boot.verifiedbootstate");
+ final String verityMode = mInjector.systemPropertiesGet("ro.boot.veritymode");
+ SecurityLog.writeEvent(SecurityLog.TAG_OS_STARTUP, verifiedBootState, verityMode);
+ }
+
private void ensureDeviceOwnerUserStarted() {
final int userId;
synchronized (this) {
@@ -3874,14 +3885,17 @@
Preconditions.checkNotNull(who, "ComponentName is null");
validateQualityConstant(quality);
+ final int userId = mInjector.userHandleGetCallingUserId();
synchronized (this) {
ActiveAdmin ap = getActiveAdminForCallerLocked(
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
- if (ap.minimumPasswordMetrics.quality != quality) {
- ap.minimumPasswordMetrics.quality = quality;
- updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ final PasswordMetrics metrics = ap.minimumPasswordMetrics;
+ if (metrics.quality != quality) {
+ metrics.quality = quality;
+ updatePasswordValidityCheckpointLocked(userId);
+ saveSettingsLocked(userId);
}
+ maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
}
@@ -3974,14 +3988,17 @@
return;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userId = mInjector.userHandleGetCallingUserId();
synchronized (this) {
ActiveAdmin ap = getActiveAdminForCallerLocked(
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
- if (ap.minimumPasswordMetrics.length != length) {
- ap.minimumPasswordMetrics.length = length;
- updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ final PasswordMetrics metrics = ap.minimumPasswordMetrics;
+ if (metrics.length != length) {
+ metrics.length = length;
+ updatePasswordValidityCheckpointLocked(userId);
+ saveSettingsLocked(userId);
}
+ maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
}
@@ -3997,15 +4014,21 @@
return;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userId = mInjector.userHandleGetCallingUserId();
synchronized (this) {
ActiveAdmin ap = getActiveAdminForCallerLocked(
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
if (ap.passwordHistoryLength != length) {
ap.passwordHistoryLength = length;
- updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ updatePasswordValidityCheckpointLocked(userId);
+ saveSettingsLocked(userId);
}
}
+ if (SecurityLog.isLoggingEnabled()) {
+ final int affectedUserId = parent ? getProfileParentId(userId) : userId;
+ SecurityLog.writeEvent(SecurityLog.TAG_PASSWORD_HISTORY_LENGTH_SET,
+ who.getPackageName(), userId, affectedUserId, length);
+ }
}
@Override
@@ -4039,6 +4062,11 @@
// in case this is the first one, set the alarm on the appropriate user.
setExpirationAlarmCheckLocked(mContext, userHandle, parent);
}
+ if (SecurityLog.isLoggingEnabled()) {
+ final int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
+ SecurityLog.writeEvent(SecurityLog.TAG_PASSWORD_EXPIRATION_SET, who.getPackageName(),
+ userHandle, affectedUserId, timeout);
+ }
}
/**
@@ -4187,14 +4215,17 @@
return;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userId = mInjector.userHandleGetCallingUserId();
synchronized (this) {
- ActiveAdmin ap = getActiveAdminForCallerLocked(
+ final ActiveAdmin ap = getActiveAdminForCallerLocked(
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
- if (ap.minimumPasswordMetrics.upperCase != length) {
- ap.minimumPasswordMetrics.upperCase = length;
- updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ final PasswordMetrics metrics = ap.minimumPasswordMetrics;
+ if (metrics.upperCase != length) {
+ metrics.upperCase = length;
+ updatePasswordValidityCheckpointLocked(userId);
+ saveSettingsLocked(userId);
}
+ maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
}
@@ -4207,14 +4238,17 @@
@Override
public void setPasswordMinimumLowerCase(ComponentName who, int length, boolean parent) {
Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userId = mInjector.userHandleGetCallingUserId();
synchronized (this) {
ActiveAdmin ap = getActiveAdminForCallerLocked(
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
- if (ap.minimumPasswordMetrics.lowerCase != length) {
- ap.minimumPasswordMetrics.lowerCase = length;
- updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ final PasswordMetrics metrics = ap.minimumPasswordMetrics;
+ if (metrics.lowerCase != length) {
+ metrics.lowerCase = length;
+ updatePasswordValidityCheckpointLocked(userId);
+ saveSettingsLocked(userId);
}
+ maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
}
@@ -4230,14 +4264,17 @@
return;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userId = mInjector.userHandleGetCallingUserId();
synchronized (this) {
ActiveAdmin ap = getActiveAdminForCallerLocked(
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
- if (ap.minimumPasswordMetrics.letters != length) {
- ap.minimumPasswordMetrics.letters = length;
- updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ final PasswordMetrics metrics = ap.minimumPasswordMetrics;
+ if (metrics.letters != length) {
+ metrics.letters = length;
+ updatePasswordValidityCheckpointLocked(userId);
+ saveSettingsLocked(userId);
}
+ maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
}
@@ -4253,14 +4290,17 @@
return;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userId = mInjector.userHandleGetCallingUserId();
synchronized (this) {
ActiveAdmin ap = getActiveAdminForCallerLocked(
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
- if (ap.minimumPasswordMetrics.numeric != length) {
- ap.minimumPasswordMetrics.numeric = length;
- updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ final PasswordMetrics metrics = ap.minimumPasswordMetrics;
+ if (metrics.numeric != length) {
+ metrics.numeric = length;
+ updatePasswordValidityCheckpointLocked(userId);
+ saveSettingsLocked(userId);
}
+ maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
}
@@ -4268,7 +4308,7 @@
public int getPasswordMinimumNumeric(ComponentName who, int userHandle, boolean parent) {
return getStrictestPasswordRequirement(who, userHandle, parent,
admin -> admin.minimumPasswordMetrics.numeric, PASSWORD_QUALITY_COMPLEX);
- }
+ }
@Override
public void setPasswordMinimumSymbols(ComponentName who, int length, boolean parent) {
@@ -4276,14 +4316,17 @@
return;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userId = mInjector.userHandleGetCallingUserId();
synchronized (this) {
ActiveAdmin ap = getActiveAdminForCallerLocked(
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
- if (ap.minimumPasswordMetrics.symbols != length) {
+ final PasswordMetrics metrics = ap.minimumPasswordMetrics;
+ if (metrics.symbols != length) {
ap.minimumPasswordMetrics.symbols = length;
- updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ updatePasswordValidityCheckpointLocked(userId);
+ saveSettingsLocked(userId);
}
+ maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
}
@@ -4299,14 +4342,17 @@
return;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userId = mInjector.userHandleGetCallingUserId();
synchronized (this) {
ActiveAdmin ap = getActiveAdminForCallerLocked(
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
- if (ap.minimumPasswordMetrics.nonLetter != length) {
+ final PasswordMetrics metrics = ap.minimumPasswordMetrics;
+ if (metrics.nonLetter != length) {
ap.minimumPasswordMetrics.nonLetter = length;
- updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ updatePasswordValidityCheckpointLocked(userId);
+ saveSettingsLocked(userId);
}
+ maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
}
@@ -4593,6 +4639,7 @@
return;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userId = mInjector.userHandleGetCallingUserId();
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
@@ -4602,9 +4649,14 @@
who, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
if (ap.maximumFailedPasswordsForWipe != num) {
ap.maximumFailedPasswordsForWipe = num;
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ saveSettingsLocked(userId);
}
}
+ if (SecurityLog.isLoggingEnabled()) {
+ final int affectedUserId = parent ? getProfileParentId(userId) : userId;
+ SecurityLog.writeEvent(SecurityLog.TAG_MAX_PASSWORD_ATTEMPTS_SET, who.getPackageName(),
+ userId, affectedUserId, num);
+ }
}
@Override
@@ -4702,7 +4754,6 @@
return false;
}
}
-
@Override
public boolean resetPassword(String passwordOrNull, int flags) throws RemoteException {
final int callingUid = mInjector.binderGetCallingUid();
@@ -4958,6 +5009,11 @@
updateMaximumTimeToLockLocked(userHandle);
}
}
+ if (SecurityLog.isLoggingEnabled()) {
+ final int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
+ SecurityLog.writeEvent(SecurityLog.TAG_MAX_SCREEN_LOCK_TIMEOUT_SET,
+ who.getPackageName(), userHandle, affectedUserId, timeMs);
+ }
}
private void updateMaximumTimeToLockLocked(@UserIdInt int userId) {
@@ -5127,11 +5183,12 @@
final long ident = mInjector.binderClearCallingIdentity();
try {
+ final ComponentName adminComponent = admin.info.getComponent();
// Evict key
if ((flags & DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY) != 0) {
enforceManagedProfile(
callingUserId, "set FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY");
- if (!isProfileOwner(admin.info.getComponent(), callingUserId)) {
+ if (!isProfileOwner(adminComponent, callingUserId)) {
throw new SecurityException("Only profile owner admins can set "
+ "FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY");
}
@@ -5161,6 +5218,13 @@
} else {
mInjector.getTrustManager().setDeviceLockedForUser(userToLock, true);
}
+
+ if (SecurityLog.isLoggingEnabled()) {
+ final int affectedUserId =
+ parent ? getProfileParentId(callingUserId) : callingUserId;
+ SecurityLog.writeEvent(SecurityLog.TAG_REMOTE_LOCK,
+ adminComponent.getPackageName(), callingUserId, affectedUserId);
+ }
} catch (RemoteException e) {
} finally {
mInjector.binderRestoreCallingIdentity(ident);
@@ -6191,8 +6255,7 @@
if (mInjector.securityLogIsLoggingEnabled()) {
SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT,
- /*result*/ 0,
- /*method strength*/ 1);
+ /*result*/ 0, /*method strength*/ 1);
}
}
@@ -7039,6 +7102,11 @@
saveSettingsLocked(userHandle);
}
}
+ if (SecurityLog.isLoggingEnabled()) {
+ final int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
+ SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISABLED_FEATURES_SET,
+ who.getPackageName(), userHandle, affectedUserId, which);
+ }
}
/**
@@ -9186,6 +9254,12 @@
}
saveUserRestrictionsLocked(userHandle);
}
+ if (SecurityLog.isLoggingEnabled()) {
+ final int eventTag = enabledFromThisOwner
+ ? SecurityLog.TAG_USER_RESTRICTION_ADDED
+ : SecurityLog.TAG_USER_RESTRICTION_REMOVED;
+ SecurityLog.writeEvent(eventTag, who.getPackageName(), userHandle, key);
+ }
}
private void saveUserRestrictionsLocked(int userId) {
@@ -12959,4 +13033,15 @@
TRANSFER_OWNERSHIP_PARAMETERS_XML);
parametersFile.delete();
}
+
+ private void maybeLogPasswordComplexitySet(ComponentName who, int userId, boolean parent,
+ PasswordMetrics metrics) {
+ if (SecurityLog.isLoggingEnabled()) {
+ final int affectedUserId = parent ? getProfileParentId(userId) : userId;
+ SecurityLog.writeEvent(SecurityLog.TAG_PASSWORD_COMPLEXITY_SET, who.getPackageName(),
+ userId, affectedUserId, metrics.length, metrics.quality, metrics.letters,
+ metrics.nonLetter, metrics.numeric, metrics.upperCase, metrics.lowerCase,
+ metrics.symbols);
+ }
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
index a9fd8e5..3277adf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
@@ -71,6 +71,10 @@
*/
private static final int BUFFER_ENTRIES_MAXIMUM_LEVEL = BUFFER_ENTRIES_NOTIFICATION_LEVEL * 10;
/**
+ * Critical log buffer level, 90% of capacity.
+ */
+ private static final int BUFFER_ENTRIES_CRITICAL_LEVEL = BUFFER_ENTRIES_MAXIMUM_LEVEL * 9 / 10;
+ /**
* How often should Device Owner be notified under normal circumstances.
*/
private static final long RATE_LIMIT_INTERVAL_MILLISECONDS = TimeUnit.HOURS.toMillis(2);
@@ -97,6 +101,10 @@
@GuardedBy("mLock")
private boolean mAllowedToRetrieve = false;
+ // Whether we have already logged the fact that log buffer reached 90%, to avoid dupes.
+ @GuardedBy("mLock")
+ private boolean mCriticalLevelLogged = false;
+
/**
* Last events fetched from log to check for overlap between batches. We can leave it empty if
* we are sure there will be no overlap anymore, e.g. when we get empty batch.
@@ -116,10 +124,12 @@
void start() {
Slog.i(TAG, "Starting security logging.");
+ SecurityLog.writeEvent(SecurityLog.TAG_LOGGING_STARTED);
mLock.lock();
try {
if (mMonitorThread == null) {
mPendingLogs = new ArrayList<>();
+ mCriticalLevelLogged = false;
mId = 0;
mAllowedToRetrieve = false;
mNextAllowedRetrievalTimeMillis = -1;
@@ -135,6 +145,7 @@
void stop() {
Slog.i(TAG, "Stopping security logging.");
+ SecurityLog.writeEvent(SecurityLog.TAG_LOGGING_STOPPED);
mLock.lock();
try {
if (mMonitorThread != null) {
@@ -205,6 +216,7 @@
mLock.lock();
mAllowedToRetrieve = false;
mPendingLogs = new ArrayList<>();
+ mCriticalLevelLogged = false;
mLock.unlock();
Slog.i(TAG, "Discarded all logs.");
}
@@ -222,6 +234,7 @@
+ RATE_LIMIT_INTERVAL_MILLISECONDS;
List<SecurityEvent> result = mPendingLogs;
mPendingLogs = new ArrayList<>();
+ mCriticalLevelLogged = false;
return result;
} else {
return null;
@@ -344,11 +357,14 @@
// Save the rest of the new batch.
mPendingLogs.addAll(idLogs);
+ checkCriticalLevel();
+
if (mPendingLogs.size() > BUFFER_ENTRIES_MAXIMUM_LEVEL) {
// Truncate buffer down to half of BUFFER_ENTRIES_MAXIMUM_LEVEL.
mPendingLogs = new ArrayList<>(mPendingLogs.subList(
mPendingLogs.size() - (BUFFER_ENTRIES_MAXIMUM_LEVEL / 2),
mPendingLogs.size()));
+ mCriticalLevelLogged = false;
Slog.i(TAG, "Pending logs buffer full. Discarding old logs.");
}
if (DEBUG) Slog.d(TAG, mPendingLogs.size() + " pending events in the buffer after merging,"
@@ -357,6 +373,20 @@
}
@GuardedBy("mLock")
+ private void checkCriticalLevel() {
+ if (!SecurityLog.isLoggingEnabled()) {
+ return;
+ }
+
+ if (mPendingLogs.size() >= BUFFER_ENTRIES_CRITICAL_LEVEL) {
+ if (!mCriticalLevelLogged) {
+ mCriticalLevelLogged = true;
+ SecurityLog.writeEvent(SecurityLog.TAG_LOG_BUFFER_SIZE_CRITICAL);
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
private void assignLogId(SecurityEvent event) {
event.setId(mId);
if (mId == Long.MAX_VALUE) {