Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2007-2014 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 <log/log_event_list.h>
     20 
     21 #include <log/log.h>
     22 
     23 #include "JNIHelp.h"
     24 #include "core_jni_helpers.h"
     25 #include "jni.h"
     26 
     27 #define UNUSED  __attribute__((__unused__))
     28 
     29 namespace android {
     30 
     31 static jclass gCollectionClass;
     32 static jmethodID gCollectionAddID;
     33 
     34 static jclass gEventClass;
     35 static jmethodID gEventInitID;
     36 
     37 static jclass gIntegerClass;
     38 static jfieldID gIntegerValueID;
     39 
     40 static jclass gLongClass;
     41 static jfieldID gLongValueID;
     42 
     43 static jclass gFloatClass;
     44 static jfieldID gFloatValueID;
     45 
     46 static jclass gStringClass;
     47 
     48 /*
     49  * In class android.util.EventLog:
     50  *  static native int writeEvent(int tag, int value)
     51  */
     52 static jint android_util_EventLog_writeEvent_Integer(JNIEnv* env UNUSED,
     53                                                      jobject clazz UNUSED,
     54                                                      jint tag, jint value)
     55 {
     56     android_log_event_list ctx(tag);
     57     ctx << (int32_t)value;
     58     return ctx.write();
     59 }
     60 
     61 /*
     62  * In class android.util.EventLog:
     63  *  static native int writeEvent(long tag, long value)
     64  */
     65 static jint android_util_EventLog_writeEvent_Long(JNIEnv* env UNUSED,
     66                                                   jobject clazz UNUSED,
     67                                                   jint tag, jlong value)
     68 {
     69     android_log_event_list ctx(tag);
     70     ctx << (int64_t)value;
     71     return ctx.write();
     72 }
     73 
     74 /*
     75  * In class android.util.EventLog:
     76  *  static native int writeEvent(long tag, float value)
     77  */
     78 static jint android_util_EventLog_writeEvent_Float(JNIEnv* env UNUSED,
     79                                                   jobject clazz UNUSED,
     80                                                   jint tag, jfloat value)
     81 {
     82     android_log_event_list ctx(tag);
     83     ctx << (float)value;
     84     return ctx.write();
     85 }
     86 
     87 /*
     88  * In class android.util.EventLog:
     89  *  static native int writeEvent(int tag, String value)
     90  */
     91 static jint android_util_EventLog_writeEvent_String(JNIEnv* env,
     92                                                     jobject clazz UNUSED,
     93                                                     jint tag, jstring value) {
     94     android_log_event_list ctx(tag);
     95     // Don't throw NPE -- I feel like it's sort of mean for a logging function
     96     // to be all crashy if you pass in NULL -- but make the NULL value explicit.
     97     if (value != NULL) {
     98         const char *str = env->GetStringUTFChars(value, NULL);
     99         ctx << str;
    100         env->ReleaseStringUTFChars(value, str);
    101     } else {
    102         ctx << "NULL";
    103     }
    104     return ctx.write();
    105 }
    106 
    107 /*
    108  * In class android.util.EventLog:
    109  *  static native int writeEvent(long tag, Object... value)
    110  */
    111 static jint android_util_EventLog_writeEvent_Array(JNIEnv* env, jobject clazz,
    112                                                    jint tag, jobjectArray value) {
    113     android_log_event_list ctx(tag);
    114 
    115     if (value == NULL) {
    116         ctx << "[NULL]";
    117         return ctx.write();
    118     }
    119 
    120     jsize copied = 0, num = env->GetArrayLength(value);
    121     for (; copied < num && copied < 255; ++copied) {
    122         if (ctx.status()) break;
    123         jobject item = env->GetObjectArrayElement(value, copied);
    124         if (item == NULL) {
    125             ctx << "NULL";
    126         } else if (env->IsInstanceOf(item, gStringClass)) {
    127             const char *str = env->GetStringUTFChars((jstring) item, NULL);
    128             ctx << str;
    129             env->ReleaseStringUTFChars((jstring) item, str);
    130         } else if (env->IsInstanceOf(item, gIntegerClass)) {
    131             ctx << (int32_t)env->GetIntField(item, gIntegerValueID);
    132         } else if (env->IsInstanceOf(item, gLongClass)) {
    133             ctx << (int64_t)env->GetLongField(item, gLongValueID);
    134         } else if (env->IsInstanceOf(item, gFloatClass)) {
    135             ctx << (float)env->GetFloatField(item, gFloatValueID);
    136         } else {
    137             jniThrowException(env,
    138                     "java/lang/IllegalArgumentException",
    139                     "Invalid payload item type");
    140             return -1;
    141         }
    142         env->DeleteLocalRef(item);
    143     }
    144     return ctx.write();
    145 }
    146 
    147 static void readEvents(JNIEnv* env, int loggerMode, jintArray tags, jlong startTime, jobject out) {
    148     struct logger_list *logger_list;
    149     if (startTime) {
    150         logger_list = android_logger_list_alloc_time(loggerMode,
    151                 log_time(startTime / NS_PER_SEC, startTime % NS_PER_SEC), 0);
    152     } else {
    153         logger_list = android_logger_list_alloc(loggerMode, 0, 0);
    154     }
    155     if (!logger_list) {
    156         jniThrowIOException(env, errno);
    157         return;
    158     }
    159 
    160     if (!android_logger_open(logger_list, LOG_ID_EVENTS)) {
    161         jniThrowIOException(env, errno);
    162         android_logger_list_free(logger_list);
    163         return;
    164     }
    165 
    166     jsize tagLength = env->GetArrayLength(tags);
    167     jint *tagValues = env->GetIntArrayElements(tags, NULL);
    168 
    169     while (1) {
    170         log_msg log_msg;
    171         int ret = android_logger_list_read(logger_list, &log_msg);
    172 
    173         if (ret == 0) {
    174             break;
    175         }
    176         if (ret < 0) {
    177             if (ret == -EINTR) {
    178                 continue;
    179             }
    180             if (ret == -EINVAL) {
    181                 jniThrowException(env, "java/io/IOException", "Event too short");
    182             } else if (ret != -EAGAIN) {
    183                 jniThrowIOException(env, -ret);  // Will throw on return
    184             }
    185             break;
    186         }
    187 
    188         if (log_msg.id() != LOG_ID_EVENTS) {
    189             continue;
    190         }
    191 
    192         int32_t tag = * (int32_t *) log_msg.msg();
    193 
    194         int found = 0;
    195         for (int i = 0; !found && i < tagLength; ++i) {
    196             found = (tag == tagValues[i]);
    197         }
    198 
    199         if (found) {
    200             jsize len = ret;
    201             jbyteArray array = env->NewByteArray(len);
    202             if (array == NULL) {
    203                 break;
    204             }
    205 
    206             jbyte *bytes = env->GetByteArrayElements(array, NULL);
    207             memcpy(bytes, log_msg.buf, len);
    208             env->ReleaseByteArrayElements(array, bytes, 0);
    209 
    210             jobject event = env->NewObject(gEventClass, gEventInitID, array);
    211             if (event == NULL) {
    212                 break;
    213             }
    214 
    215             env->CallBooleanMethod(out, gCollectionAddID, event);
    216             env->DeleteLocalRef(event);
    217             env->DeleteLocalRef(array);
    218         }
    219     }
    220 
    221     android_logger_list_close(logger_list);
    222 
    223     env->ReleaseIntArrayElements(tags, tagValues, 0);
    224 }
    225 
    226 /*
    227  * In class android.util.EventLog:
    228  *  static native void readEvents(int[] tags, Collection<Event> output)
    229  *
    230  *  Reads events from the event log
    231  */
    232 static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz UNUSED,
    233                                              jintArray tags,
    234                                              jobject out) {
    235 
    236     if (tags == NULL || out == NULL) {
    237         jniThrowNullPointerException(env, NULL);
    238         return;
    239     }
    240 
    241     readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, tags, 0, out);
    242  }
    243 /*
    244  * In class android.util.EventLog:
    245  *  static native void readEventsOnWrapping(int[] tags, long timestamp, Collection<Event> output)
    246  *
    247  *  Reads events from the event log, blocking until events after timestamp are to be overwritten.
    248  */
    249 static void android_util_EventLog_readEventsOnWrapping(JNIEnv* env, jobject clazz UNUSED,
    250                                              jintArray tags,
    251                                              jlong timestamp,
    252                                              jobject out) {
    253     if (tags == NULL || out == NULL) {
    254         jniThrowNullPointerException(env, NULL);
    255         return;
    256     }
    257     readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK | ANDROID_LOG_WRAP,
    258             tags, timestamp, out);
    259 }
    260 
    261 /*
    262  * JNI registration.
    263  */
    264 static const JNINativeMethod gRegisterMethods[] = {
    265     /* name, signature, funcPtr */
    266     { "writeEvent", "(II)I", (void*) android_util_EventLog_writeEvent_Integer },
    267     { "writeEvent", "(IJ)I", (void*) android_util_EventLog_writeEvent_Long },
    268     { "writeEvent", "(IF)I", (void*) android_util_EventLog_writeEvent_Float },
    269     { "writeEvent",
    270       "(ILjava/lang/String;)I",
    271       (void*) android_util_EventLog_writeEvent_String
    272     },
    273     { "writeEvent",
    274       "(I[Ljava/lang/Object;)I",
    275       (void*) android_util_EventLog_writeEvent_Array
    276     },
    277     { "readEvents",
    278       "([ILjava/util/Collection;)V",
    279       (void*) android_util_EventLog_readEvents
    280     },
    281     { "readEventsOnWrapping",
    282       "([IJLjava/util/Collection;)V",
    283       (void*) android_util_EventLog_readEventsOnWrapping
    284     },
    285 };
    286 
    287 static struct { const char *name; jclass *clazz; } gClasses[] = {
    288     { "android/util/EventLog$Event", &gEventClass },
    289     { "java/lang/Integer", &gIntegerClass },
    290     { "java/lang/Long", &gLongClass },
    291     { "java/lang/Float", &gFloatClass },
    292     { "java/lang/String", &gStringClass },
    293     { "java/util/Collection", &gCollectionClass },
    294 };
    295 
    296 static struct { jclass *c; const char *name, *ft; jfieldID *id; } gFields[] = {
    297     { &gIntegerClass, "value", "I", &gIntegerValueID },
    298     { &gLongClass, "value", "J", &gLongValueID },
    299     { &gFloatClass, "value", "F", &gFloatValueID },
    300 };
    301 
    302 static struct { jclass *c; const char *name, *mt; jmethodID *id; } gMethods[] = {
    303     { &gEventClass, "<init>", "([B)V", &gEventInitID },
    304     { &gCollectionClass, "add", "(Ljava/lang/Object;)Z", &gCollectionAddID },
    305 };
    306 
    307 int register_android_util_EventLog(JNIEnv* env) {
    308     for (int i = 0; i < NELEM(gClasses); ++i) {
    309         jclass clazz = FindClassOrDie(env, gClasses[i].name);
    310         *gClasses[i].clazz = MakeGlobalRefOrDie(env, clazz);
    311     }
    312 
    313     for (int i = 0; i < NELEM(gFields); ++i) {
    314         *gFields[i].id = GetFieldIDOrDie(env,
    315                 *gFields[i].c, gFields[i].name, gFields[i].ft);
    316     }
    317 
    318     for (int i = 0; i < NELEM(gMethods); ++i) {
    319         *gMethods[i].id = GetMethodIDOrDie(env,
    320                 *gMethods[i].c, gMethods[i].name, gMethods[i].mt);
    321     }
    322 
    323     return RegisterMethodsOrDie(
    324             env,
    325             "android/util/EventLog",
    326             gRegisterMethods, NELEM(gRegisterMethods));
    327 }
    328 
    329 }; // namespace android
    330