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