static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jintArray outIrqs, jobjectArray outReasons) { bool first_time = false; if (outIrqs == NULL || outReasons == NULL) { jniThrowException(env, "java/lang/NullPointerException", "null argument"); return -1; } // Register our wakeup callback if not yet done. if (!wakeup_init) { wakeup_init = true; ALOGV("Creating semaphore..."); int ret = sem_init(&wakeup_sem, 0, 0); if (ret < 0) { char buf[80]; strerror_r(errno, buf, sizeof(buf)); ALOGE("Error creating semaphore: %s\n", buf); jniThrowException(env, "java/lang/IllegalStateException", buf); return -1; } ALOGV("Registering callback..."); set_wakeup_callback(&wakeup_callback); // First time through, we will just drain the current wakeup reasons. first_time = true; } else { // On following calls, we need to wait for wakeup. ALOGV("Waiting for wakeup..."); int ret = sem_wait(&wakeup_sem); if (ret < 0) { char buf[80]; strerror_r(errno, buf, sizeof(buf)); ALOGE("Error waiting on semaphore: %s\n", buf); // Return 0 here to let it continue looping but not return results. return 0; } } FILE *fp = fopen(LAST_RESUME_REASON, "r"); if (fp == NULL) { ALOGE("Failed to open %s", LAST_RESUME_REASON); return -1; } int numOut = env->GetArrayLength(outIrqs); ScopedIntArrayRW irqs(env, outIrqs); ALOGV("Reading up to %d wakeup reasons", numOut); char mergedreason[MAX_REASON_SIZE]; char* mergedreasonpos = mergedreason; int remainreasonlen = MAX_REASON_SIZE; int firstirq = 0; char reasonline[128]; int i = 0; while (fgets(reasonline, sizeof(reasonline), fp) != NULL && i < numOut) { char* pos = reasonline; char* endPos; // First field is the index. int irq = (int)strtol(pos, &endPos, 10); if (pos == endPos) { // Ooops. ALOGE("Bad reason line: %s", reasonline); continue; } pos = endPos; // Skip whitespace; rest of the buffer is the reason string. while (*pos == ' ') { pos++; } // Chop newline at end. char* endpos = pos; while (*endpos != 0) { if (*endpos == '\n') { *endpos = 0; break; } endpos++; } // For now we are not separating out the first irq. // This is because in practice there are always multiple // lines of wakeup reasons, so it is better to just treat // them all together as a single string. if (false && i == 0) { firstirq = irq; } else { int len = snprintf(mergedreasonpos, remainreasonlen, i == 0 ? "%d" : ":%d", irq); if (len >= 0 && len < remainreasonlen) { mergedreasonpos += len; remainreasonlen -= len; } } int len = snprintf(mergedreasonpos, remainreasonlen, ":%s", pos); if (len >= 0 && len < remainreasonlen) { mergedreasonpos += len; remainreasonlen -= len; } // For now it is better to combine all of these in to one entry in the // battery history. In the future, it might be nice to figure out a way // to efficiently store multiple lines as a single entry in the history. //irqs[i] = irq; //ScopedLocalRef<jstring> reasonString(env, env->NewStringUTF(pos)); //env->SetObjectArrayElement(outReasons, i, reasonString.get()); //ALOGV("Wakeup reason #%d: irw %d reason %s", i, irq, pos); i++; } ALOGV("Got %d reasons", i); if (first_time) { i = 0; } if (i > 0) { irqs[0] = firstirq; *mergedreasonpos = 0; ScopedLocalRef<jstring> reasonString(env, env->NewStringUTF(mergedreason)); env->SetObjectArrayElement(outReasons, 0, reasonString.get()); i = 1; } if (fclose(fp) != 0) { ALOGE("Failed to close %s", LAST_RESUME_REASON); return -1; } return first_time ? 0 : i; }
static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf) { if (outBuf == NULL) { jniThrowException(env, "java/lang/NullPointerException", "null argument"); return -1; } // Register our wakeup callback if not yet done. if (!wakeup_init) { wakeup_init = true; ALOGV("Creating semaphore..."); int ret = sem_init(&wakeup_sem, 0, 0); if (ret < 0) { char buf[80]; strerror_r(errno, buf, sizeof(buf)); ALOGE("Error creating semaphore: %s\n", buf); jniThrowException(env, "java/lang/IllegalStateException", buf); return -1; } ALOGV("Registering callback..."); set_wakeup_callback(&wakeup_callback); } // Wait for wakeup. ALOGV("Waiting for wakeup..."); int ret = sem_wait(&wakeup_sem); if (ret < 0) { char buf[80]; strerror_r(errno, buf, sizeof(buf)); ALOGE("Error waiting on semaphore: %s\n", buf); // Return 0 here to let it continue looping but not return results. return 0; } FILE *fp = fopen(LAST_RESUME_REASON, "r"); if (fp == NULL) { ALOGE("Failed to open %s", LAST_RESUME_REASON); return -1; } char* mergedreason = (char*)env->GetDirectBufferAddress(outBuf); int remainreasonlen = (int)env->GetDirectBufferCapacity(outBuf); ALOGV("Reading wakeup reasons"); char* mergedreasonpos = mergedreason; char reasonline[128]; int i = 0; while (fgets(reasonline, sizeof(reasonline), fp) != NULL) { char* pos = reasonline; char* endPos; int len; // First field is the index or 'Abort'. int irq = (int)strtol(pos, &endPos, 10); if (pos != endPos) { // Write the irq number to the merged reason string. len = snprintf(mergedreasonpos, remainreasonlen, i == 0 ? "%d" : ":%d", irq); } else { // The first field is not an irq, it may be the word Abort. const size_t abortPrefixLen = strlen("Abort:"); if (strncmp(pos, "Abort:", abortPrefixLen) != 0) { // Ooops. ALOGE("Bad reason line: %s", reasonline); continue; } // Write 'Abort' to the merged reason string. len = snprintf(mergedreasonpos, remainreasonlen, i == 0 ? "Abort" : ":Abort"); endPos = pos + abortPrefixLen; } pos = endPos; if (len >= 0 && len < remainreasonlen) { mergedreasonpos += len; remainreasonlen -= len; } // Skip whitespace; rest of the buffer is the reason string. while (*pos == ' ') { pos++; } // Chop newline at end. char* endpos = pos; while (*endpos != 0) { if (*endpos == '\n') { *endpos = 0; break; } endpos++; } len = snprintf(mergedreasonpos, remainreasonlen, ":%s", pos); if (len >= 0 && len < remainreasonlen) { mergedreasonpos += len; remainreasonlen -= len; } i++; } ALOGV("Got %d reasons", i); if (i > 0) { *mergedreasonpos = 0; } if (fclose(fp) != 0) { ALOGE("Failed to close %s", LAST_RESUME_REASON); return -1; } return mergedreasonpos - mergedreason; }