Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <fcntl.h>
     18 
     19 #include "JNIHelp.h"
     20 #include "android_runtime/AndroidRuntime.h"
     21 #include "jni.h"
     22 #include "log/logger.h"
     23 
     24 // The size of the tag number comes out of the payload size.
     25 #define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
     26 
     27 namespace android {
     28 
     29 static jclass gCollectionClass;
     30 static jmethodID gCollectionAddID;
     31 
     32 static jclass gEventClass;
     33 static jmethodID gEventInitID;
     34 
     35 static jclass gIntegerClass;
     36 static jfieldID gIntegerValueID;
     37 
     38 static jclass gLongClass;
     39 static jfieldID gLongValueID;
     40 
     41 static jclass gStringClass;
     42 
     43 /*
     44  * In class android.util.EventLog:
     45  *  static native int writeEvent(int tag, int value)
     46  */
     47 static jint android_util_EventLog_writeEvent_Integer(JNIEnv* env, jobject clazz,
     48                                                      jint tag, jint value)
     49 {
     50     return android_btWriteLog(tag, EVENT_TYPE_INT, &value, sizeof(value));
     51 }
     52 
     53 /*
     54  * In class android.util.EventLog:
     55  *  static native int writeEvent(long tag, long value)
     56  */
     57 static jint android_util_EventLog_writeEvent_Long(JNIEnv* env, jobject clazz,
     58                                                   jint tag, jlong value)
     59 {
     60     return android_btWriteLog(tag, EVENT_TYPE_LONG, &value, sizeof(value));
     61 }
     62 
     63 /*
     64  * In class android.util.EventLog:
     65  *  static native int writeEvent(int tag, String value)
     66  */
     67 static jint android_util_EventLog_writeEvent_String(JNIEnv* env, jobject clazz,
     68                                                     jint tag, jstring value) {
     69     uint8_t buf[MAX_EVENT_PAYLOAD];
     70 
     71     // Don't throw NPE -- I feel like it's sort of mean for a logging function
     72     // to be all crashy if you pass in NULL -- but make the NULL value explicit.
     73     const char *str = value != NULL ? env->GetStringUTFChars(value, NULL) : "NULL";
     74     uint32_t len = strlen(str);
     75     size_t max = sizeof(buf) - sizeof(len) - 2;  // Type byte, final newline
     76     if (len > max) len = max;
     77 
     78     buf[0] = EVENT_TYPE_STRING;
     79     memcpy(&buf[1], &len, sizeof(len));
     80     memcpy(&buf[1 + sizeof(len)], str, len);
     81     buf[1 + sizeof(len) + len] = '\n';
     82 
     83     if (value != NULL) env->ReleaseStringUTFChars(value, str);
     84     return android_bWriteLog(tag, buf, 2 + sizeof(len) + len);
     85 }
     86 
     87 /*
     88  * In class android.util.EventLog:
     89  *  static native int writeEvent(long tag, Object... value)
     90  */
     91 static jint android_util_EventLog_writeEvent_Array(JNIEnv* env, jobject clazz,
     92                                                    jint tag, jobjectArray value) {
     93     if (value == NULL) {
     94         return android_util_EventLog_writeEvent_String(env, clazz, tag, NULL);
     95     }
     96 
     97     uint8_t buf[MAX_EVENT_PAYLOAD];
     98     const size_t max = sizeof(buf) - 1;  // leave room for final newline
     99     size_t pos = 2;  // Save room for type tag & array count
    100 
    101     jsize copied = 0, num = env->GetArrayLength(value);
    102     for (; copied < num && copied < 255; ++copied) {
    103         jobject item = env->GetObjectArrayElement(value, copied);
    104         if (item == NULL || env->IsInstanceOf(item, gStringClass)) {
    105             if (pos + 1 + sizeof(jint) > max) break;
    106             const char *str = item != NULL ? env->GetStringUTFChars((jstring) item, NULL) : "NULL";
    107             jint len = strlen(str);
    108             if (pos + 1 + sizeof(len) + len > max) len = max - pos - 1 - sizeof(len);
    109             buf[pos++] = EVENT_TYPE_STRING;
    110             memcpy(&buf[pos], &len, sizeof(len));
    111             memcpy(&buf[pos + sizeof(len)], str, len);
    112             pos += sizeof(len) + len;
    113             if (item != NULL) env->ReleaseStringUTFChars((jstring) item, str);
    114         } else if (env->IsInstanceOf(item, gIntegerClass)) {
    115             jint intVal = env->GetIntField(item, gIntegerValueID);
    116             if (pos + 1 + sizeof(intVal) > max) break;
    117             buf[pos++] = EVENT_TYPE_INT;
    118             memcpy(&buf[pos], &intVal, sizeof(intVal));
    119             pos += sizeof(intVal);
    120         } else if (env->IsInstanceOf(item, gLongClass)) {
    121             jlong longVal = env->GetLongField(item, gLongValueID);
    122             if (pos + 1 + sizeof(longVal) > max) break;
    123             buf[pos++] = EVENT_TYPE_LONG;
    124             memcpy(&buf[pos], &longVal, sizeof(longVal));
    125             pos += sizeof(longVal);
    126         } else {
    127             jniThrowException(env,
    128                     "java/lang/IllegalArgumentException",
    129                     "Invalid payload item type");
    130             return -1;
    131         }
    132         env->DeleteLocalRef(item);
    133     }
    134 
    135     buf[0] = EVENT_TYPE_LIST;
    136     buf[1] = copied;
    137     buf[pos++] = '\n';
    138     return android_bWriteLog(tag, buf, pos);
    139 }
    140 
    141 /*
    142  * In class android.util.EventLog:
    143  *  static native void readEvents(int[] tags, Collection<Event> output)
    144  *
    145  *  Reads events from the event log, typically /dev/log/events
    146  */
    147 static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz,
    148                                              jintArray tags,
    149                                              jobject out) {
    150     if (tags == NULL || out == NULL) {
    151         jniThrowNullPointerException(env, NULL);
    152         return;
    153     }
    154 
    155     int fd = open("/dev/" LOGGER_LOG_EVENTS, O_RDONLY | O_NONBLOCK);
    156     if (fd < 0) {
    157         jniThrowIOException(env, errno);
    158         return;
    159     }
    160 
    161     jsize tagLength = env->GetArrayLength(tags);
    162     jint *tagValues = env->GetIntArrayElements(tags, NULL);
    163 
    164     uint8_t buf[LOGGER_ENTRY_MAX_LEN];
    165     struct timeval timeout = {0, 0};
    166     fd_set readset;
    167     FD_ZERO(&readset);
    168 
    169     for (;;) {
    170         // Use a short select() to try to avoid problems hanging on read().
    171         // This means we block for 5ms at the end of the log -- oh well.
    172         timeout.tv_usec = 5000;
    173         FD_SET(fd, &readset);
    174         int r = select(fd + 1, &readset, NULL, NULL, &timeout);
    175         if (r == 0) {
    176             break;  // no more events
    177         } else if (r < 0 && errno == EINTR) {
    178             continue;  // interrupted by signal, try again
    179         } else if (r < 0) {
    180             jniThrowIOException(env, errno);  // Will throw on return
    181             break;
    182         }
    183 
    184         int len = read(fd, buf, sizeof(buf));
    185         if (len == 0 || (len < 0 && errno == EAGAIN)) {
    186             break;  // no more events
    187         } else if (len < 0 && errno == EINTR) {
    188             continue;  // interrupted by signal, try again
    189         } else if (len < 0) {
    190             jniThrowIOException(env, errno);  // Will throw on return
    191             break;
    192         } else if ((size_t) len < sizeof(logger_entry) + sizeof(int32_t)) {
    193             jniThrowException(env, "java/io/IOException", "Event too short");
    194             break;
    195         }
    196 
    197         logger_entry* entry = (logger_entry*) buf;
    198         int32_t tag = * (int32_t*) (buf + sizeof(*entry));
    199 
    200         int found = 0;
    201         for (int i = 0; !found && i < tagLength; ++i) {
    202             found = (tag == tagValues[i]);
    203         }
    204 
    205         if (found) {
    206             jsize len = sizeof(*entry) + entry->len;
    207             jbyteArray array = env->NewByteArray(len);
    208             if (array == NULL) break;
    209 
    210             jbyte *bytes = env->GetByteArrayElements(array, NULL);
    211             memcpy(bytes, buf, len);
    212             env->ReleaseByteArrayElements(array, bytes, 0);
    213 
    214             jobject event = env->NewObject(gEventClass, gEventInitID, array);
    215             if (event == NULL) break;
    216 
    217             env->CallBooleanMethod(out, gCollectionAddID, event);
    218             env->DeleteLocalRef(event);
    219             env->DeleteLocalRef(array);
    220         }
    221     }
    222 
    223     close(fd);
    224     env->ReleaseIntArrayElements(tags, tagValues, 0);
    225 }
    226 
    227 /*
    228  * JNI registration.
    229  */
    230 static JNINativeMethod gRegisterMethods[] = {
    231     /* name, signature, funcPtr */
    232     { "writeEvent", "(II)I", (void*) android_util_EventLog_writeEvent_Integer },
    233     { "writeEvent", "(IJ)I", (void*) android_util_EventLog_writeEvent_Long },
    234     { "writeEvent",
    235       "(ILjava/lang/String;)I",
    236       (void*) android_util_EventLog_writeEvent_String
    237     },
    238     { "writeEvent",
    239       "(I[Ljava/lang/Object;)I",
    240       (void*) android_util_EventLog_writeEvent_Array
    241     },
    242     { "readEvents",
    243       "([ILjava/util/Collection;)V",
    244       (void*) android_util_EventLog_readEvents
    245     },
    246 };
    247 
    248 static struct { const char *name; jclass *clazz; } gClasses[] = {
    249     { "android/util/EventLog$Event", &gEventClass },
    250     { "java/lang/Integer", &gIntegerClass },
    251     { "java/lang/Long", &gLongClass },
    252     { "java/lang/String", &gStringClass },
    253     { "java/util/Collection", &gCollectionClass },
    254 };
    255 
    256 static struct { jclass *c; const char *name, *ft; jfieldID *id; } gFields[] = {
    257     { &gIntegerClass, "value", "I", &gIntegerValueID },
    258     { &gLongClass, "value", "J", &gLongValueID },
    259 };
    260 
    261 static struct { jclass *c; const char *name, *mt; jmethodID *id; } gMethods[] = {
    262     { &gEventClass, "<init>", "([B)V", &gEventInitID },
    263     { &gCollectionClass, "add", "(Ljava/lang/Object;)Z", &gCollectionAddID },
    264 };
    265 
    266 int register_android_util_EventLog(JNIEnv* env) {
    267     for (int i = 0; i < NELEM(gClasses); ++i) {
    268         jclass clazz = env->FindClass(gClasses[i].name);
    269         if (clazz == NULL) {
    270             ALOGE("Can't find class: %s\n", gClasses[i].name);
    271             return -1;
    272         }
    273         *gClasses[i].clazz = (jclass) env->NewGlobalRef(clazz);
    274     }
    275 
    276     for (int i = 0; i < NELEM(gFields); ++i) {
    277         *gFields[i].id = env->GetFieldID(
    278                 *gFields[i].c, gFields[i].name, gFields[i].ft);
    279         if (*gFields[i].id == NULL) {
    280             ALOGE("Can't find field: %s\n", gFields[i].name);
    281             return -1;
    282         }
    283     }
    284 
    285     for (int i = 0; i < NELEM(gMethods); ++i) {
    286         *gMethods[i].id = env->GetMethodID(
    287                 *gMethods[i].c, gMethods[i].name, gMethods[i].mt);
    288         if (*gMethods[i].id == NULL) {
    289             ALOGE("Can't find method: %s\n", gMethods[i].name);
    290             return -1;
    291         }
    292     }
    293 
    294     return AndroidRuntime::registerNativeMethods(
    295             env,
    296             "android/util/EventLog",
    297             gRegisterMethods, NELEM(gRegisterMethods));
    298 }
    299 
    300 }; // namespace android
    301