blob: 25249663835a0c5e172be393ade60f9481611490 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 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 "BatteryService"
18
19#include "JNIHelp.h"
20#include "jni.h"
21#include "utils/Log.h"
22#include "utils/misc.h"
23
24#include <fcntl.h>
25#include <stdio.h>
26#include <string.h>
27#include <sys/types.h>
28#include <sys/socket.h>
29#include <arpa/inet.h>
30#include <netinet/in.h>
31#include <stdlib.h>
32#include <errno.h>
33#include <unistd.h>
34
35#if HAVE_ANDROID_OS
36#include <linux/ioctl.h>
37#endif
38
39namespace android {
40
41#define AC_ONLINE_PATH "/sys/class/power_supply/ac/online"
42#define USB_ONLINE_PATH "/sys/class/power_supply/usb/online"
43#define BATTERY_STATUS_PATH "/sys/class/power_supply/battery/status"
44#define BATTERY_HEALTH_PATH "/sys/class/power_supply/battery/health"
45#define BATTERY_PRESENT_PATH "/sys/class/power_supply/battery/present"
46#define BATTERY_CAPACITY_PATH "/sys/class/power_supply/battery/capacity"
47#define BATTERY_VOLTAGE_PATH "/sys/class/power_supply/battery/batt_vol"
48#define BATTERY_TEMPERATURE_PATH "/sys/class/power_supply/battery/batt_temp"
49#define BATTERY_TECHNOLOGY_PATH "/sys/class/power_supply/battery/technology"
50
51struct FieldIds {
52 // members
53 jfieldID mAcOnline;
54 jfieldID mUsbOnline;
55 jfieldID mBatteryStatus;
56 jfieldID mBatteryHealth;
57 jfieldID mBatteryPresent;
58 jfieldID mBatteryLevel;
59 jfieldID mBatteryVoltage;
60 jfieldID mBatteryTemperature;
61 jfieldID mBatteryTechnology;
62};
63static FieldIds gFieldIds;
64
65struct BatteryManagerConstants {
66 jint statusUnknown;
67 jint statusCharging;
68 jint statusDischarging;
69 jint statusNotCharging;
70 jint statusFull;
71 jint healthUnknown;
72 jint healthGood;
73 jint healthOverheat;
74 jint healthDead;
75 jint healthOverVoltage;
76 jint healthUnspecifiedFailure;
77};
78static BatteryManagerConstants gConstants;
79
80static jint getBatteryStatus(const char* status)
81{
82 switch (status[0]) {
83 case 'C': return gConstants.statusCharging; // Charging
84 case 'D': return gConstants.statusDischarging; // Discharging
85 case 'F': return gConstants.statusFull; // Not charging
86 case 'N': return gConstants.statusNotCharging; // Full
87 case 'U': return gConstants.statusUnknown; // Unknown
88
89 default: {
90 LOGW("Unknown battery status '%s'", status);
91 return gConstants.statusUnknown;
92 }
93 }
94}
95
96static jint getBatteryHealth(const char* status)
97{
98 switch (status[0]) {
99 case 'D': return gConstants.healthDead; // Dead
100 case 'G': return gConstants.healthGood; // Good
101 case 'O': {
102 if (strcmp(status, "Overheat") == 0) {
103 return gConstants.healthOverheat;
104 } else if (strcmp(status, "Over voltage") == 0) {
105 return gConstants.healthOverVoltage;
106 }
107 LOGW("Unknown battery health[1] '%s'", status);
108 return gConstants.healthUnknown;
109 }
110
111 case 'U': {
112 if (strcmp(status, "Unspecified failure") == 0) {
113 return gConstants.healthUnspecifiedFailure;
114 } else if (strcmp(status, "Unknown") == 0) {
115 return gConstants.healthUnknown;
116 }
117 // fall through
118 }
119
120 default: {
121 LOGW("Unknown battery health[2] '%s'", status);
122 return gConstants.healthUnknown;
123 }
124 }
125}
126
127static int readFromFile(const char* path, char* buf, size_t size)
128{
129 int fd = open(path, O_RDONLY, 0);
130 if (fd == -1) {
131 LOGE("Could not open '%s'", path);
132 return -1;
133 }
134
135 size_t count = read(fd, buf, size);
136 if (count > 0) {
137 count = (count < size) ? count : size - 1;
138 while (count > 0 && buf[count-1] == '\n') count--;
139 buf[count] = '\0';
140 } else {
141 buf[0] = '\0';
142 }
143
144 close(fd);
145 return count;
146}
147
148static void setBooleanField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
149{
150 const int SIZE = 16;
151 char buf[SIZE];
152
153 jboolean value = false;
154 if (readFromFile(path, buf, SIZE) > 0) {
155 if (buf[0] == '1') {
156 value = true;
157 }
158 }
159 env->SetBooleanField(obj, fieldID, value);
160}
161
162static void setIntField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
163{
164 const int SIZE = 128;
165 char buf[SIZE];
166
167 jint value = 0;
168 if (readFromFile(path, buf, SIZE) > 0) {
169 value = atoi(buf);
170 }
171 env->SetIntField(obj, fieldID, value);
172}
173
174static void android_server_BatteryService_update(JNIEnv* env, jobject obj)
175{
176 setBooleanField(env, obj, AC_ONLINE_PATH, gFieldIds.mAcOnline);
177 setBooleanField(env, obj, USB_ONLINE_PATH, gFieldIds.mUsbOnline);
178 setBooleanField(env, obj, BATTERY_PRESENT_PATH, gFieldIds.mBatteryPresent);
179
180 setIntField(env, obj, BATTERY_CAPACITY_PATH, gFieldIds.mBatteryLevel);
181 setIntField(env, obj, BATTERY_VOLTAGE_PATH, gFieldIds.mBatteryVoltage);
182 setIntField(env, obj, BATTERY_TEMPERATURE_PATH, gFieldIds.mBatteryTemperature);
183
184 const int SIZE = 128;
185 char buf[SIZE];
186
187 if (readFromFile(BATTERY_STATUS_PATH, buf, SIZE) > 0)
188 env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf));
Rebecca Schultz Zavine7e6fa32009-04-28 17:24:47 -0700189 else
190 env->SetIntField(obj, gFieldIds.mBatteryStatus,
191 gConstants.statusUnknown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192
193 if (readFromFile(BATTERY_HEALTH_PATH, buf, SIZE) > 0)
194 env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf));
195
196 if (readFromFile(BATTERY_TECHNOLOGY_PATH, buf, SIZE) > 0)
197 env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf));
198}
199
200static JNINativeMethod sMethods[] = {
201 /* name, signature, funcPtr */
202 {"native_update", "()V", (void*)android_server_BatteryService_update},
203};
204
205int register_android_server_BatteryService(JNIEnv* env)
206{
207 jclass clazz = env->FindClass("com/android/server/BatteryService");
208
209 if (clazz == NULL) {
210 LOGE("Can't find com/android/server/BatteryService");
211 return -1;
212 }
213
214 gFieldIds.mAcOnline = env->GetFieldID(clazz, "mAcOnline", "Z");
215 gFieldIds.mUsbOnline = env->GetFieldID(clazz, "mUsbOnline", "Z");
216 gFieldIds.mBatteryStatus = env->GetFieldID(clazz, "mBatteryStatus", "I");
217 gFieldIds.mBatteryHealth = env->GetFieldID(clazz, "mBatteryHealth", "I");
218 gFieldIds.mBatteryPresent = env->GetFieldID(clazz, "mBatteryPresent", "Z");
219 gFieldIds.mBatteryLevel = env->GetFieldID(clazz, "mBatteryLevel", "I");
220 gFieldIds.mBatteryTechnology = env->GetFieldID(clazz, "mBatteryTechnology", "Ljava/lang/String;");
221 gFieldIds.mBatteryVoltage = env->GetFieldID(clazz, "mBatteryVoltage", "I");
222 gFieldIds.mBatteryTemperature = env->GetFieldID(clazz, "mBatteryTemperature", "I");
223
224 LOG_FATAL_IF(gFieldIds.mAcOnline == NULL, "Unable to find BatteryService.AC_ONLINE_PATH");
225 LOG_FATAL_IF(gFieldIds.mUsbOnline == NULL, "Unable to find BatteryService.USB_ONLINE_PATH");
226 LOG_FATAL_IF(gFieldIds.mBatteryStatus == NULL, "Unable to find BatteryService.BATTERY_STATUS_PATH");
227 LOG_FATAL_IF(gFieldIds.mBatteryHealth == NULL, "Unable to find BatteryService.BATTERY_HEALTH_PATH");
228 LOG_FATAL_IF(gFieldIds.mBatteryPresent == NULL, "Unable to find BatteryService.BATTERY_PRESENT_PATH");
229 LOG_FATAL_IF(gFieldIds.mBatteryLevel == NULL, "Unable to find BatteryService.BATTERY_CAPACITY_PATH");
230 LOG_FATAL_IF(gFieldIds.mBatteryVoltage == NULL, "Unable to find BatteryService.BATTERY_VOLTAGE_PATH");
231 LOG_FATAL_IF(gFieldIds.mBatteryTemperature == NULL, "Unable to find BatteryService.BATTERY_TEMPERATURE_PATH");
232 LOG_FATAL_IF(gFieldIds.mBatteryTechnology == NULL, "Unable to find BatteryService.BATTERY_TECHNOLOGY_PATH");
233
234 clazz = env->FindClass("android/os/BatteryManager");
235
236 if (clazz == NULL) {
237 LOGE("Can't find android/os/BatteryManager");
238 return -1;
239 }
240
241 gConstants.statusUnknown = env->GetStaticIntField(clazz,
242 env->GetStaticFieldID(clazz, "BATTERY_STATUS_UNKNOWN", "I"));
243
244 gConstants.statusCharging = env->GetStaticIntField(clazz,
245 env->GetStaticFieldID(clazz, "BATTERY_STATUS_CHARGING", "I"));
246
247 gConstants.statusDischarging = env->GetStaticIntField(clazz,
248 env->GetStaticFieldID(clazz, "BATTERY_STATUS_DISCHARGING", "I"));
249
250 gConstants.statusNotCharging = env->GetStaticIntField(clazz,
251 env->GetStaticFieldID(clazz, "BATTERY_STATUS_NOT_CHARGING", "I"));
252
253 gConstants.statusFull = env->GetStaticIntField(clazz,
254 env->GetStaticFieldID(clazz, "BATTERY_STATUS_FULL", "I"));
255
256 gConstants.healthUnknown = env->GetStaticIntField(clazz,
257 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNKNOWN", "I"));
258
259 gConstants.healthGood = env->GetStaticIntField(clazz,
260 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_GOOD", "I"));
261
262 gConstants.healthOverheat = env->GetStaticIntField(clazz,
263 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_OVERHEAT", "I"));
264
265 gConstants.healthDead = env->GetStaticIntField(clazz,
266 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_DEAD", "I"));
267
268 gConstants.healthOverVoltage = env->GetStaticIntField(clazz,
269 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_OVER_VOLTAGE", "I"));
270
271 gConstants.healthUnspecifiedFailure = env->GetStaticIntField(clazz,
272 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNSPECIFIED_FAILURE", "I"));
273
274 return jniRegisterNativeMethods(env, "com/android/server/BatteryService", sMethods, NELEM(sMethods));
275}
276
277} /* namespace android */