• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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  */
android_util_EventLog_writeEvent_Integer(JNIEnv * env,jobject clazz,jint tag,jint value)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  */
android_util_EventLog_writeEvent_Long(JNIEnv * env,jobject clazz,jint tag,jlong value)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  */
android_util_EventLog_writeEvent_String(JNIEnv * env,jobject clazz,jint tag,jstring value)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     jint len = strlen(str);
75     const int 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  */
android_util_EventLog_writeEvent_Array(JNIEnv * env,jobject clazz,jint tag,jobjectArray value)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  */
android_util_EventLog_readEvents(JNIEnv * env,jobject clazz,jintArray tags,jobject out)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 
register_android_util_EventLog(JNIEnv * env)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             LOGE("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             LOGE("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             LOGE("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