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  */
android_util_EventLog_writeEvent_Integer(JNIEnv * env UNUSED,jobject clazz UNUSED,jint tag,jint value)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  */
android_util_EventLog_writeEvent_Long(JNIEnv * env UNUSED,jobject clazz UNUSED,jint tag,jlong value)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  */
android_util_EventLog_writeEvent_Float(JNIEnv * env UNUSED,jobject clazz UNUSED,jint tag,jfloat value)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  */
android_util_EventLog_writeEvent_String(JNIEnv * env,jobject clazz UNUSED,jint tag,jstring value)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  */
android_util_EventLog_writeEvent_Array(JNIEnv * env,jobject clazz,jint tag,jobjectArray value)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 
readEvents(JNIEnv * env,int loggerMode,jintArray tags,jlong startTime,jobject out)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  */
android_util_EventLog_readEvents(JNIEnv * env,jobject clazz UNUSED,jintArray tags,jobject out)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  */
android_util_EventLog_readEventsOnWrapping(JNIEnv * env,jobject clazz UNUSED,jintArray tags,jlong timestamp,jobject out)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 
register_android_util_EventLog(JNIEnv * env)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