From 75431fbe361e16cfdc43c16cc65b86b8dab39e82 Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Thu, 7 Jan 2016 21:12:14 +0000 Subject: [PATCH] Add JNI bridge to the new logd security buffer. Bug: 26127031 Bug: 22860162 Change-Id: I14e08850ece7d9c0229b7213ee2e25cd089defc1 --- Android.mk | 1 + api/current.txt | 24 ++ api/system-current.txt | 24 ++ api/test-current.txt | 24 ++ core/java/android/auditing/SecurityLog.java | 210 ++++++++++++ .../android/auditing/SecurityLogTags.logtags | 11 + core/java/android/util/EventLog.java | 12 + core/jni/Android.mk | 1 + core/jni/AndroidRuntime.cpp | 2 + core/jni/android_auditing_SecurityLog.cpp | 312 ++++++++++++++++++ 10 files changed, 621 insertions(+) create mode 100644 core/java/android/auditing/SecurityLog.java create mode 100644 core/java/android/auditing/SecurityLogTags.logtags create mode 100644 core/jni/android_auditing_SecurityLog.cpp diff --git a/Android.mk b/Android.mk index e4f40afece51c..de15f5c46407a 100644 --- a/Android.mk +++ b/Android.mk @@ -42,6 +42,7 @@ LOCAL_SRC_FILES := $(call find-other-java-files,$(FRAMEWORKS_BASE_SUBDIRS)) # EventLogTags files. LOCAL_SRC_FILES += \ + core/java/android/auditing/SecurityLogTags.logtags \ core/java/android/content/EventLogTags.logtags \ core/java/android/speech/tts/EventLogTags.logtags \ core/java/android/webkit/EventLogTags.logtags \ diff --git a/api/current.txt b/api/current.txt index 358d4d5176f77..9080e6dc76d43 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6467,6 +6467,30 @@ package android.appwidget { } +package android.auditing { + + public class SecurityLog { + ctor public SecurityLog(); + 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_DEVICE_LOCKED = 210007; // 0x33457 + field public static final int TAG_DEVICE_UNLOCK_ATTEMPT = 210006; // 0x33456 + field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453 + field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454 + } + + public static class SecurityLog.SecurityEvent implements android.os.Parcelable { + method public int describeContents(); + method public java.lang.Object getData(); + method public int getTag(); + method public long getTimeNanos(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + } + +} + package android.bluetooth { public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile { diff --git a/api/system-current.txt b/api/system-current.txt index 9b66945ecbc91..9eed46e08b18c 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -6691,6 +6691,30 @@ package android.appwidget { } +package android.auditing { + + public class SecurityLog { + ctor public SecurityLog(); + 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_DEVICE_LOCKED = 210007; // 0x33457 + field public static final int TAG_DEVICE_UNLOCK_ATTEMPT = 210006; // 0x33456 + field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453 + field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454 + } + + public static class SecurityLog.SecurityEvent implements android.os.Parcelable { + method public int describeContents(); + method public java.lang.Object getData(); + method public int getTag(); + method public long getTimeNanos(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + } + +} + package android.bluetooth { public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile { diff --git a/api/test-current.txt b/api/test-current.txt index 41a77b3c8a92d..8b4ada800a82f 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -6469,6 +6469,30 @@ package android.appwidget { } +package android.auditing { + + public class SecurityLog { + ctor public SecurityLog(); + 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_DEVICE_LOCKED = 210007; // 0x33457 + field public static final int TAG_DEVICE_UNLOCK_ATTEMPT = 210006; // 0x33456 + field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453 + field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454 + } + + public static class SecurityLog.SecurityEvent implements android.os.Parcelable { + method public int describeContents(); + method public java.lang.Object getData(); + method public int getTag(); + method public long getTimeNanos(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + } + +} + package android.bluetooth { public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile { diff --git a/core/java/android/auditing/SecurityLog.java b/core/java/android/auditing/SecurityLog.java new file mode 100644 index 0000000000000..87dc1d85cd06e --- /dev/null +++ b/core/java/android/auditing/SecurityLog.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2016 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 android.auditing; + +import android.annotation.IntDef; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.SystemProperties; +import android.util.EventLog.Event; + +import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Collection; + +public class SecurityLog { + + private static final String PROPERTY_LOGGING_ENABLED = "persist.logd.security"; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({TAG_ADB_SHELL_INTERACTIVE, TAG_ADB_SHELL_CMD, TAG_SYNC_RECV_FILE, TAG_SYNC_SEND_FILE, + TAG_APP_PROCESS_START, TAG_DEVICE_UNLOCK_ATTEMPT, TAG_DEVICE_LOCKED}) + public @interface SECURITY_LOG_TAG {} + + /** + * Indicate 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()} + */ + 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()} + */ + 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()} + */ + 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 + * information about the process in order, 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 APK in hexadecimal (String) + */ + public static final int TAG_APP_PROCESS_START = SecurityLogTags.SECURITY_APP_PROCESS_START; + + /** + * Indicate that there has been an attempt to unlock the device. The log entry contains the + * following information about the attempt in order, accessible via + * {@link SecurityEvent#getData()}}: unlock result (integer, 1 for successful unlock, 0 for + * unsuccessful), unlock method (String) + */ + public static final int TAG_DEVICE_UNLOCK_ATTEMPT = + SecurityLogTags.SECURITY_DEVICE_UNLOCK_ATTEMPT; + + /** + * Indicate that the device has been locked, either by user or by timeout. + */ + public static final int TAG_DEVICE_LOCKED = SecurityLogTags.SECURITY_DEVICE_LOCKED; + + + /** + * Returns if device 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}. + * @hide + */ + public static native boolean isLoggingEnabled(); + + /** + * @hide + */ + public static void setLoggingEnabledProperty(boolean enabled) { + SystemProperties.set(PROPERTY_LOGGING_ENABLED, enabled ? "true" : "false"); + } + + /** + * @hide + */ + public static boolean getLoggingEnabledProperty() { + return SystemProperties.getBoolean(PROPERTY_LOGGING_ENABLED, false); + } + + /** + * A class representing a security event log entry. + */ + public static class SecurityEvent implements Parcelable { + private Event mEvent; + + /** @hide */ + /*package*/ SecurityEvent(byte[] data) { + mEvent = Event.fromBytes(data); + } + + /** + * Returns the timestamp in nano seconds when this event was logged. + */ + public long getTimeNanos() { + return mEvent.getTimeNanos(); + } + + /** + * Returns the tag of this log entry, which specifies entry's semantics. + * Could be one of {@link SecurityLog#TAG_SYNC_RECV_FILE}, + * {@link SecurityLog#TAG_SYNC_SEND_FILE}, {@link SecurityLog#TAG_ADB_SHELL_CMD}, + * {@link SecurityLog#TAG_ADB_SHELL_INTERACTIVE}, {@link SecurityLog#TAG_APP_PROCESS_START}. + */ + public @SECURITY_LOG_TAG int getTag() { + return mEvent.getTag(); + } + + /** + * Returns the payload contained in this log. Each call to this method will + * retrieve the next payload item. If no more payload exists, it returns {@code null}. + */ + public Object getData() { + return mEvent.getData(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeByteArray(mEvent.getBytes()); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public SecurityEvent createFromParcel(Parcel source) { + return new SecurityEvent(source.createByteArray()); + } + + @Override + public SecurityEvent[] newArray(int size) { + return new SecurityEvent[size]; + } + }; + } + /** + * Retrieve all security logs and return immediately. + * @hide + */ + public static native void readEvents(Collection output) throws IOException; + + /** + * Retrieve all security logs since the given timestamp in nanoseconds and return immediately. + * @hide + */ + public static native void readEventsSince(long timestamp, Collection output) + throws IOException; + + /** + * Retrieve all security logs before the last reboot. May return corrupted data due to + * unreliable pstore. + * @hide + */ + public static native void readPreviousEvents(Collection output) + 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 + * timestamp is about to be pruned, or after a 2-hour timeout has passed. + * @hide + */ + public static native void readEventsOnWrapping(long timestamp, Collection output) + throws IOException; + + /** + * Write a log entry to the underlying storage, with a string payload. + * @hide + */ + public static native int writeEvent(int tag, String str); + + /** + * Write a log entry to the underlying storage, with several payloads. + * Supported types of payload are: integer, long, float, string plus array of supported types. + * @hide + */ + public static native int writeEvent(int tag, Object... payloads); +} diff --git a/core/java/android/auditing/SecurityLogTags.logtags b/core/java/android/auditing/SecurityLogTags.logtags new file mode 100644 index 0000000000000..455acff3048ea --- /dev/null +++ b/core/java/android/auditing/SecurityLogTags.logtags @@ -0,0 +1,11 @@ +# See system/core/logcat/event.logtags for a description of the format of this file. + +option java_package android.auditing + +210001 security_adb_shell_interactive +210002 security_adb_shell_command (command|3) +210003 security_adb_sync_recv (path|3) +210004 security_adb_sync_send (path|3) +210005 security_app_process_start (process|3),(start_time|2|3),(uid|1),(pid|1),(seinfo|3),(sha256|3) +210006 security_device_unlock_attempt (success|1),(method|3) +210007 security_device_locked \ No newline at end of file diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java index 6bda83d2b3156..6196a97024e63 100644 --- a/core/java/android/util/EventLog.java +++ b/core/java/android/util/EventLog.java @@ -23,6 +23,7 @@ import java.io.UnsupportedEncodingException; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.regex.Matcher; @@ -161,6 +162,17 @@ public class EventLog { throw new IllegalArgumentException("Unknown entry type: " + type); } } + + /** @hide */ + public static Event fromBytes(byte[] data) { + return new Event(data); + } + + /** @hide */ + public byte[] getBytes() { + byte[] bytes = mBuffer.array(); + return Arrays.copyOf(bytes, bytes.length); + } } // We assume that the native methods deal with any concurrency issues. diff --git a/core/jni/Android.mk b/core/jni/Android.mk index fc1ba44394435..644ecc6e9901b 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -34,6 +34,7 @@ LOCAL_SRC_FILES:= \ com_google_android_gles_jni_EGLImpl.cpp \ com_google_android_gles_jni_GLImpl.cpp.arm \ android_app_NativeActivity.cpp \ + android_auditing_SecurityLog.cpp \ android_opengl_EGL14.cpp \ android_opengl_EGLExt.cpp \ android_opengl_GLES10.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 63f193d57419c..109b4924a98d6 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -108,6 +108,7 @@ namespace android { * JNI-based registration functions. Note these are properly contained in * namespace android. */ +extern int register_android_auditing_SecurityLog(JNIEnv* env); extern int register_android_content_AssetManager(JNIEnv* env); extern int register_android_util_EventLog(JNIEnv* env); extern int register_android_util_Log(JNIEnv* env); @@ -1244,6 +1245,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_util_EventLog), REG_JNI(register_android_util_Log), REG_JNI(register_android_util_PathParser), + REG_JNI(register_android_auditing_SecurityLog), REG_JNI(register_android_content_AssetManager), REG_JNI(register_android_content_StringBlock), REG_JNI(register_android_content_XmlBlock), diff --git a/core/jni/android_auditing_SecurityLog.cpp b/core/jni/android_auditing_SecurityLog.cpp new file mode 100644 index 0000000000000..78f04cd2ed414 --- /dev/null +++ b/core/jni/android_auditing_SecurityLog.cpp @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2016 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. + */ + +#include + +#include "JNIHelp.h" +#include "core_jni_helpers.h" +#include "jni.h" +#include "log/logger.h" + +// The size of the tag number comes out of the payload size. +#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t)) + +namespace android { + +static jclass gCollectionClass; +static jmethodID gCollectionAddID; + +static jclass gEventClass; +static jmethodID gEventInitID; + +static jclass gIntegerClass; +static jfieldID gIntegerValueID; + +static jclass gLongClass; +static jfieldID gLongValueID; + +static jclass gFloatClass; +static jfieldID gFloatValueID; + +static jclass gStringClass; + + +static jboolean android_auditing_SecurityLog_isLoggingEnabled(JNIEnv* env, + jobject /* clazz */) { + return (bool)__android_log_security(); +} + +static jint android_auditing_SecurityLog_writeEvent_String(JNIEnv* env, + jobject /* clazz */, + jint tag, jstring value) { + uint8_t buf[MAX_EVENT_PAYLOAD]; + + // Don't throw NPE -- I feel like it's sort of mean for a logging function + // to be all crashy if you pass in NULL -- but make the NULL value explicit. + const char *str = value != NULL ? env->GetStringUTFChars(value, NULL) : "NULL"; + uint32_t len = strlen(str); + size_t max = sizeof(buf) - sizeof(len) - 2; // Type byte, final newline + if (len > max) len = max; + + buf[0] = EVENT_TYPE_STRING; + memcpy(&buf[1], &len, sizeof(len)); + memcpy(&buf[1 + sizeof(len)], str, len); + buf[1 + sizeof(len) + len] = '\n'; + + if (value != NULL) env->ReleaseStringUTFChars(value, str); + return __android_log_security_bwrite(tag, buf, 2 + sizeof(len) + len); +} + +static jint android_auditing_SecurityLog_writeEvent_Array(JNIEnv* env, jobject clazz, + jint tag, jobjectArray value) { + if (value == NULL) { + return android_auditing_SecurityLog_writeEvent_String(env, clazz, tag, NULL); + } + + uint8_t buf[MAX_EVENT_PAYLOAD]; + const size_t max = sizeof(buf) - 1; // leave room for final newline + size_t pos = 2; // Save room for type tag & array count + + jsize copied = 0, num = env->GetArrayLength(value); + for (; copied < num && copied < 255; ++copied) { + jobject item = env->GetObjectArrayElement(value, copied); + if (item == NULL || env->IsInstanceOf(item, gStringClass)) { + if (pos + 1 + sizeof(jint) > max) break; + const char *str = item != NULL ? env->GetStringUTFChars((jstring) item, NULL) : "NULL"; + jint len = strlen(str); + if (pos + 1 + sizeof(len) + len > max) len = max - pos - 1 - sizeof(len); + buf[pos++] = EVENT_TYPE_STRING; + memcpy(&buf[pos], &len, sizeof(len)); + memcpy(&buf[pos + sizeof(len)], str, len); + pos += sizeof(len) + len; + if (item != NULL) env->ReleaseStringUTFChars((jstring) item, str); + } else if (env->IsInstanceOf(item, gIntegerClass)) { + jint intVal = env->GetIntField(item, gIntegerValueID); + if (pos + 1 + sizeof(intVal) > max) break; + buf[pos++] = EVENT_TYPE_INT; + memcpy(&buf[pos], &intVal, sizeof(intVal)); + pos += sizeof(intVal); + } else if (env->IsInstanceOf(item, gLongClass)) { + jlong longVal = env->GetLongField(item, gLongValueID); + if (pos + 1 + sizeof(longVal) > max) break; + buf[pos++] = EVENT_TYPE_LONG; + memcpy(&buf[pos], &longVal, sizeof(longVal)); + pos += sizeof(longVal); + } else if (env->IsInstanceOf(item, gFloatClass)) { + jfloat floatVal = env->GetFloatField(item, gFloatValueID); + if (pos + 1 + sizeof(floatVal) > max) break; + buf[pos++] = EVENT_TYPE_FLOAT; + memcpy(&buf[pos], &floatVal, sizeof(floatVal)); + pos += sizeof(floatVal); + } else { + jniThrowException(env, + "java/lang/IllegalArgumentException", + "Invalid payload item type"); + return -1; + } + env->DeleteLocalRef(item); + } + + buf[0] = EVENT_TYPE_LIST; + buf[1] = copied; + buf[pos++] = '\n'; + return __android_log_security_bwrite(tag, buf, pos); +} + +static void readEvents(JNIEnv* env, int loggerMode, jlong startTime, jobject out) { + struct logger_list *logger_list; + if (startTime) { + logger_list = android_logger_list_alloc_time(loggerMode, + log_time(startTime / NS_PER_SEC, startTime % NS_PER_SEC), 0); + } else { + logger_list = android_logger_list_alloc(loggerMode, 0, 0); + } + if (!logger_list) { + jniThrowIOException(env, errno); + return; + } + + if (!android_logger_open(logger_list, LOG_ID_SECURITY)) { + jniThrowIOException(env, errno); + android_logger_list_free(logger_list); + return; + } + + while (1) { + log_msg log_msg; + int ret = android_logger_list_read(logger_list, &log_msg); + + if (ret == 0) { + break; + } + if (ret < 0) { + if (ret == -EINTR) { + continue; + } + if (ret == -EINVAL) { + jniThrowException(env, "java/io/IOException", "Event too short"); + } else if (ret != -EAGAIN) { + jniThrowIOException(env, -ret); // Will throw on return + } + break; + } + + if (log_msg.id() != LOG_ID_SECURITY) { + continue; + } + + jsize len = ret; + jbyteArray array = env->NewByteArray(len); + if (array == NULL) { + break; + } + + jbyte *bytes = env->GetByteArrayElements(array, NULL); + memcpy(bytes, log_msg.buf, len); + env->ReleaseByteArrayElements(array, bytes, 0); + + jobject event = env->NewObject(gEventClass, gEventInitID, array); + if (event == NULL) { + break; + } + + env->CallBooleanMethod(out, gCollectionAddID, event); + env->DeleteLocalRef(event); + env->DeleteLocalRef(array); + } + + android_logger_list_close(logger_list); +} + +static void android_auditing_SecurityLog_readEvents(JNIEnv* env, jobject /* clazz */, + jobject out) { + + if (out == NULL) { + jniThrowNullPointerException(env, NULL); + return; + } + readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, out); +} + +static void android_auditing_SecurityLog_readEventsSince(JNIEnv* env, jobject /* clazz */, + jlong timestamp, + jobject out) { + + if (out == NULL) { + jniThrowNullPointerException(env, NULL); + return; + } + readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, timestamp, out); +} + +static void android_auditing_SecurityLog_readPreviousEvents(JNIEnv* env, jobject /* clazz */, + jobject out) { + + if (out == NULL) { + jniThrowNullPointerException(env, NULL); + return; + } + readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK | ANDROID_LOG_PSTORE, 0, out); +} + +static void android_auditing_SecurityLog_readEventsOnWrapping(JNIEnv* env, jobject /* clazz */, + jlong timestamp, + jobject out) { + if (out == NULL) { + jniThrowNullPointerException(env, NULL); + return; + } + readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK | ANDROID_LOG_WRAP, timestamp, out); +} + +/* + * JNI registration. + */ +static const JNINativeMethod gRegisterMethods[] = { + /* name, signature, funcPtr */ + { "isLoggingEnabled", + "()Z", + (void*) android_auditing_SecurityLog_isLoggingEnabled + }, + { "writeEvent", + "(ILjava/lang/String;)I", + (void*) android_auditing_SecurityLog_writeEvent_String + }, + { "writeEvent", + "(I[Ljava/lang/Object;)I", + (void*) android_auditing_SecurityLog_writeEvent_Array + }, + { "readEvents", + "(Ljava/util/Collection;)V", + (void*) android_auditing_SecurityLog_readEvents + }, + { "readEventsSince", + "(JLjava/util/Collection;)V", + (void*) android_auditing_SecurityLog_readEventsSince + }, + { "readPreviousEvents", + "(Ljava/util/Collection;)V", + (void*) android_auditing_SecurityLog_readPreviousEvents + }, + { "readEventsOnWrapping", + "(JLjava/util/Collection;)V", + (void*) android_auditing_SecurityLog_readEventsOnWrapping + }, +}; + +static struct { const char *name; jclass *clazz; } gClasses[] = { + { "android/auditing/SecurityLog$SecurityEvent", &gEventClass }, + { "java/lang/Integer", &gIntegerClass }, + { "java/lang/Long", &gLongClass }, + { "java/lang/Float", &gFloatClass }, + { "java/lang/String", &gStringClass }, + { "java/util/Collection", &gCollectionClass }, +}; + +static struct { jclass *c; const char *name, *ft; jfieldID *id; } gFields[] = { + { &gIntegerClass, "value", "I", &gIntegerValueID }, + { &gLongClass, "value", "J", &gLongValueID }, + { &gFloatClass, "value", "F", &gFloatValueID }, +}; + +static struct { jclass *c; const char *name, *mt; jmethodID *id; } gMethods[] = { + { &gEventClass, "", "([B)V", &gEventInitID }, + { &gCollectionClass, "add", "(Ljava/lang/Object;)Z", &gCollectionAddID }, +}; + +int register_android_auditing_SecurityLog(JNIEnv* env) { + for (int i = 0; i < NELEM(gClasses); ++i) { + jclass clazz = FindClassOrDie(env, gClasses[i].name); + *gClasses[i].clazz = MakeGlobalRefOrDie(env, clazz); + } + + for (int i = 0; i < NELEM(gFields); ++i) { + *gFields[i].id = GetFieldIDOrDie(env, + *gFields[i].c, gFields[i].name, gFields[i].ft); + } + + for (int i = 0; i < NELEM(gMethods); ++i) { + *gMethods[i].id = GetMethodIDOrDie(env, + *gMethods[i].c, gMethods[i].name, gMethods[i].mt); + } + + return RegisterMethodsOrDie( + env, + "android/auditing/SecurityLog", + gRegisterMethods, NELEM(gRegisterMethods)); +} + +}; // namespace android