blob: 5c43659796440231ee69314d6d790740c7921545 [file] [log] [blame]
Dianne Hackbornc51cf032014-03-02 19:08:15 -08001/*
2 * Copyright (C) 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#define LOG_TAG "BatteryStatsService"
18//#define LOG_NDEBUG 0
19
20#include <android_runtime/AndroidRuntime.h>
21#include <jni.h>
22
23#include <ScopedLocalRef.h>
24#include <ScopedPrimitiveArray.h>
25
26#include <cutils/log.h>
27#include <utils/misc.h>
28#include <utils/Log.h>
29#include <hardware/hardware.h>
30#include <suspend/autosuspend.h>
31
32#include <stdio.h>
33#include <errno.h>
34#include <fcntl.h>
35#include <semaphore.h>
36#include <stddef.h>
37#include <string.h>
38#include <sys/stat.h>
39#include <sys/types.h>
40#include <unistd.h>
41
42namespace android
43{
44
45#define LAST_RESUME_REASON "/sys/kernel/wakeup_reasons/last_resume_reason"
46#define MAX_REASON_SIZE 512
47
48static bool wakeup_init = false;
49static sem_t wakeup_sem;
50
Adam Lesinski87fd3222015-06-25 13:10:36 -070051static void wakeup_callback(bool success)
Dianne Hackbornc51cf032014-03-02 19:08:15 -080052{
Adam Lesinski87fd3222015-06-25 13:10:36 -070053 ALOGV("In wakeup_callback: %s", success ? "resumed from suspend" : "suspend aborted");
Dianne Hackbornc51cf032014-03-02 19:08:15 -080054 int ret = sem_post(&wakeup_sem);
55 if (ret < 0) {
56 char buf[80];
57 strerror_r(errno, buf, sizeof(buf));
58 ALOGE("Error posting wakeup sem: %s\n", buf);
59 }
60}
61
Adam Lesinski515702c2015-07-23 18:13:38 -070062static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf)
Dianne Hackbornc51cf032014-03-02 19:08:15 -080063{
Adam Lesinski515702c2015-07-23 18:13:38 -070064 if (outBuf == NULL) {
Dianne Hackbornc51cf032014-03-02 19:08:15 -080065 jniThrowException(env, "java/lang/NullPointerException", "null argument");
66 return -1;
67 }
68
69 // Register our wakeup callback if not yet done.
70 if (!wakeup_init) {
71 wakeup_init = true;
72 ALOGV("Creating semaphore...");
73 int ret = sem_init(&wakeup_sem, 0, 0);
74 if (ret < 0) {
75 char buf[80];
76 strerror_r(errno, buf, sizeof(buf));
77 ALOGE("Error creating semaphore: %s\n", buf);
78 jniThrowException(env, "java/lang/IllegalStateException", buf);
79 return -1;
80 }
81 ALOGV("Registering callback...");
82 set_wakeup_callback(&wakeup_callback);
Adam Lesinski6b0331a2015-06-05 17:08:22 -070083 }
84
85 // Wait for wakeup.
86 ALOGV("Waiting for wakeup...");
87 int ret = sem_wait(&wakeup_sem);
88 if (ret < 0) {
89 char buf[80];
90 strerror_r(errno, buf, sizeof(buf));
91 ALOGE("Error waiting on semaphore: %s\n", buf);
92 // Return 0 here to let it continue looping but not return results.
93 return 0;
Dianne Hackbornc51cf032014-03-02 19:08:15 -080094 }
95
96 FILE *fp = fopen(LAST_RESUME_REASON, "r");
97 if (fp == NULL) {
98 ALOGE("Failed to open %s", LAST_RESUME_REASON);
99 return -1;
100 }
101
Adam Lesinski515702c2015-07-23 18:13:38 -0700102 char* mergedreason = (char*)env->GetDirectBufferAddress(outBuf);
103 int remainreasonlen = (int)env->GetDirectBufferCapacity(outBuf);
Dianne Hackbornc51cf032014-03-02 19:08:15 -0800104
Adam Lesinski515702c2015-07-23 18:13:38 -0700105 ALOGV("Reading wakeup reasons");
Dianne Hackbornc51cf032014-03-02 19:08:15 -0800106 char* mergedreasonpos = mergedreason;
Dianne Hackbornc51cf032014-03-02 19:08:15 -0800107 char reasonline[128];
108 int i = 0;
Adam Lesinski87fd3222015-06-25 13:10:36 -0700109 while (fgets(reasonline, sizeof(reasonline), fp) != NULL) {
Dianne Hackbornc51cf032014-03-02 19:08:15 -0800110 char* pos = reasonline;
111 char* endPos;
Adam Lesinski87fd3222015-06-25 13:10:36 -0700112 int len;
113 // First field is the index or 'Abort'.
Dianne Hackbornc51cf032014-03-02 19:08:15 -0800114 int irq = (int)strtol(pos, &endPos, 10);
Adam Lesinski87fd3222015-06-25 13:10:36 -0700115 if (pos != endPos) {
116 // Write the irq number to the merged reason string.
117 len = snprintf(mergedreasonpos, remainreasonlen, i == 0 ? "%d" : ":%d", irq);
118 } else {
119 // The first field is not an irq, it may be the word Abort.
120 const size_t abortPrefixLen = strlen("Abort:");
121 if (strncmp(pos, "Abort:", abortPrefixLen) != 0) {
122 // Ooops.
123 ALOGE("Bad reason line: %s", reasonline);
124 continue;
125 }
126
127 // Write 'Abort' to the merged reason string.
128 len = snprintf(mergedreasonpos, remainreasonlen, i == 0 ? "Abort" : ":Abort");
129 endPos = pos + abortPrefixLen;
Dianne Hackbornc51cf032014-03-02 19:08:15 -0800130 }
131 pos = endPos;
Adam Lesinski87fd3222015-06-25 13:10:36 -0700132
133 if (len >= 0 && len < remainreasonlen) {
134 mergedreasonpos += len;
135 remainreasonlen -= len;
136 }
137
Dianne Hackbornc51cf032014-03-02 19:08:15 -0800138 // Skip whitespace; rest of the buffer is the reason string.
139 while (*pos == ' ') {
140 pos++;
141 }
Adam Lesinski87fd3222015-06-25 13:10:36 -0700142
Dianne Hackbornc51cf032014-03-02 19:08:15 -0800143 // Chop newline at end.
144 char* endpos = pos;
145 while (*endpos != 0) {
146 if (*endpos == '\n') {
147 *endpos = 0;
148 break;
149 }
150 endpos++;
151 }
Adam Lesinski87fd3222015-06-25 13:10:36 -0700152
153 len = snprintf(mergedreasonpos, remainreasonlen, ":%s", pos);
Dianne Hackbornc51cf032014-03-02 19:08:15 -0800154 if (len >= 0 && len < remainreasonlen) {
155 mergedreasonpos += len;
156 remainreasonlen -= len;
157 }
Dianne Hackbornc51cf032014-03-02 19:08:15 -0800158 i++;
159 }
160
161 ALOGV("Got %d reasons", i);
Dianne Hackbornc51cf032014-03-02 19:08:15 -0800162 if (i > 0) {
Dianne Hackbornc51cf032014-03-02 19:08:15 -0800163 *mergedreasonpos = 0;
Dianne Hackbornc51cf032014-03-02 19:08:15 -0800164 }
165
166 if (fclose(fp) != 0) {
167 ALOGE("Failed to close %s", LAST_RESUME_REASON);
168 return -1;
169 }
Adam Lesinski515702c2015-07-23 18:13:38 -0700170 return mergedreasonpos - mergedreason;
Dianne Hackbornc51cf032014-03-02 19:08:15 -0800171}
172
Daniel Micay76f6a862015-09-19 17:31:01 -0400173static const JNINativeMethod method_table[] = {
Adam Lesinski515702c2015-07-23 18:13:38 -0700174 { "nativeWaitWakeup", "(Ljava/nio/ByteBuffer;)I", (void*)nativeWaitWakeup },
Dianne Hackbornc51cf032014-03-02 19:08:15 -0800175};
176
177int register_android_server_BatteryStatsService(JNIEnv *env)
178{
179 return jniRegisterNativeMethods(env, "com/android/server/am/BatteryStatsService",
180 method_table, NELEM(method_table));
181}
182
183};