2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #define LOG_TAG "BatteryService"
21 #include <utils/Log.h>
22 #include <utils/misc.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <arpa/inet.h>
30 #include <netinet/in.h>
36 #ifdef HAVE_ANDROID_OS
37 #include <linux/ioctl.h>
42 #define POWER_SUPPLY_PATH "/sys/class/power_supply"
48 jfieldID mBatteryStatus;
49 jfieldID mBatteryHealth;
50 jfieldID mBatteryPresent;
51 jfieldID mBatteryLevel;
52 jfieldID mBatteryVoltage;
53 jfieldID mBatteryTemperature;
54 jfieldID mBatteryTechnology;
56 static FieldIds gFieldIds;
58 struct BatteryManagerConstants {
61 jint statusDischarging;
62 jint statusNotCharging;
68 jint healthOverVoltage;
69 jint healthUnspecifiedFailure;
72 static BatteryManagerConstants gConstants;
74 struct PowerSupplyPaths {
77 char* batteryStatusPath;
78 char* batteryHealthPath;
79 char* batteryPresentPath;
80 char* batteryCapacityPath;
81 char* batteryVoltagePath;
82 char* batteryTemperaturePath;
83 char* batteryTechnologyPath;
85 static PowerSupplyPaths gPaths;
87 static int gVoltageDivisor = 1;
89 static jint getBatteryStatus(const char* status)
92 case 'C': return gConstants.statusCharging; // Charging
93 case 'D': return gConstants.statusDischarging; // Discharging
94 case 'F': return gConstants.statusFull; // Not charging
95 case 'N': return gConstants.statusNotCharging; // Full
96 case 'U': return gConstants.statusUnknown; // Unknown
99 LOGW("Unknown battery status '%s'", status);
100 return gConstants.statusUnknown;
105 static jint getBatteryHealth(const char* status)
108 case 'C': return gConstants.healthCold; // Cold
109 case 'D': return gConstants.healthDead; // Dead
110 case 'G': return gConstants.healthGood; // Good
112 if (strcmp(status, "Overheat") == 0) {
113 return gConstants.healthOverheat;
114 } else if (strcmp(status, "Over voltage") == 0) {
115 return gConstants.healthOverVoltage;
117 LOGW("Unknown battery health[1] '%s'", status);
118 return gConstants.healthUnknown;
122 if (strcmp(status, "Unspecified failure") == 0) {
123 return gConstants.healthUnspecifiedFailure;
124 } else if (strcmp(status, "Unknown") == 0) {
125 return gConstants.healthUnknown;
131 LOGW("Unknown battery health[2] '%s'", status);
132 return gConstants.healthUnknown;
137 static int readFromFile(const char* path, char* buf, size_t size)
141 int fd = open(path, O_RDONLY, 0);
143 LOGE("Could not open '%s'", path);
147 size_t count = read(fd, buf, size);
149 count = (count < size) ? count : size - 1;
150 while (count > 0 && buf[count-1] == '\n') count--;
160 static void setBooleanField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
165 jboolean value = false;
166 if (readFromFile(path, buf, SIZE) > 0) {
171 env->SetBooleanField(obj, fieldID, value);
174 static void setIntField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
176 const int SIZE = 128;
180 if (readFromFile(path, buf, SIZE) > 0) {
183 env->SetIntField(obj, fieldID, value);
186 static void setVoltageField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
188 const int SIZE = 128;
192 if (readFromFile(path, buf, SIZE) > 0) {
194 value /= gVoltageDivisor;
196 env->SetIntField(obj, fieldID, value);
200 static void android_server_BatteryService_update(JNIEnv* env, jobject obj)
202 setBooleanField(env, obj, gPaths.acOnlinePath, gFieldIds.mAcOnline);
203 setBooleanField(env, obj, gPaths.usbOnlinePath, gFieldIds.mUsbOnline);
204 setBooleanField(env, obj, gPaths.batteryPresentPath, gFieldIds.mBatteryPresent);
206 setIntField(env, obj, gPaths.batteryCapacityPath, gFieldIds.mBatteryLevel);
207 setVoltageField(env, obj, gPaths.batteryVoltagePath, gFieldIds.mBatteryVoltage);
208 setIntField(env, obj, gPaths.batteryTemperaturePath, gFieldIds.mBatteryTemperature);
210 const int SIZE = 128;
213 if (readFromFile(gPaths.batteryStatusPath, buf, SIZE) > 0)
214 env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf));
216 env->SetIntField(obj, gFieldIds.mBatteryStatus,
217 gConstants.statusUnknown);
219 if (readFromFile(gPaths.batteryHealthPath, buf, SIZE) > 0)
220 env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf));
222 if (readFromFile(gPaths.batteryTechnologyPath, buf, SIZE) > 0)
223 env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf));
226 static JNINativeMethod sMethods[] = {
227 /* name, signature, funcPtr */
228 {"native_update", "()V", (void*)android_server_BatteryService_update},
231 int register_android_server_BatteryService(JNIEnv* env)
234 struct dirent* entry;
236 DIR* dir = opendir(POWER_SUPPLY_PATH);
238 LOGE("Could not open %s\n", POWER_SUPPLY_PATH);
241 while ((entry = readdir(dir))) {
242 const char* name = entry->d_name;
244 // ignore "." and ".."
245 if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
250 // Look for "type" file in each subdirectory
251 snprintf(path, sizeof(path), "%s/%s/type", POWER_SUPPLY_PATH, name);
252 int length = readFromFile(path, buf, sizeof(buf));
254 if (buf[length - 1] == '\n')
257 if (strcmp(buf, "Mains") == 0) {
258 snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
259 if (access(path, R_OK) == 0)
260 gPaths.acOnlinePath = strdup(path);
262 else if (strcmp(buf, "USB") == 0) {
263 snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
264 if (access(path, R_OK) == 0)
265 gPaths.usbOnlinePath = strdup(path);
267 else if (strcmp(buf, "Battery") == 0) {
268 snprintf(path, sizeof(path), "%s/%s/status", POWER_SUPPLY_PATH, name);
269 if (access(path, R_OK) == 0)
270 gPaths.batteryStatusPath = strdup(path);
271 snprintf(path, sizeof(path), "%s/%s/health", POWER_SUPPLY_PATH, name);
272 if (access(path, R_OK) == 0)
273 gPaths.batteryHealthPath = strdup(path);
274 snprintf(path, sizeof(path), "%s/%s/present", POWER_SUPPLY_PATH, name);
275 if (access(path, R_OK) == 0)
276 gPaths.batteryPresentPath = strdup(path);
277 snprintf(path, sizeof(path), "%s/%s/capacity", POWER_SUPPLY_PATH, name);
278 if (access(path, R_OK) == 0)
279 gPaths.batteryCapacityPath = strdup(path);
281 snprintf(path, sizeof(path), "%s/%s/voltage_now", POWER_SUPPLY_PATH, name);
282 if (access(path, R_OK) == 0) {
283 gPaths.batteryVoltagePath = strdup(path);
284 // voltage_now is in microvolts, not millivolts
285 gVoltageDivisor = 1000;
287 snprintf(path, sizeof(path), "%s/%s/batt_vol", POWER_SUPPLY_PATH, name);
288 if (access(path, R_OK) == 0)
289 gPaths.batteryVoltagePath = strdup(path);
292 snprintf(path, sizeof(path), "%s/%s/temp", POWER_SUPPLY_PATH, name);
293 if (access(path, R_OK) == 0) {
294 gPaths.batteryTemperaturePath = strdup(path);
296 snprintf(path, sizeof(path), "%s/%s/batt_temp", POWER_SUPPLY_PATH, name);
297 if (access(path, R_OK) == 0)
298 gPaths.batteryTemperaturePath = strdup(path);
301 snprintf(path, sizeof(path), "%s/%s/technology", POWER_SUPPLY_PATH, name);
302 if (access(path, R_OK) == 0)
303 gPaths.batteryTechnologyPath = strdup(path);
309 if (!gPaths.acOnlinePath)
310 LOGE("acOnlinePath not found");
311 if (!gPaths.usbOnlinePath)
312 LOGE("usbOnlinePath not found");
313 if (!gPaths.batteryStatusPath)
314 LOGE("batteryStatusPath not found");
315 if (!gPaths.batteryHealthPath)
316 LOGE("batteryHealthPath not found");
317 if (!gPaths.batteryPresentPath)
318 LOGE("batteryPresentPath not found");
319 if (!gPaths.batteryCapacityPath)
320 LOGE("batteryCapacityPath not found");
321 if (!gPaths.batteryVoltagePath)
322 LOGE("batteryVoltagePath not found");
323 if (!gPaths.batteryTemperaturePath)
324 LOGE("batteryTemperaturePath not found");
325 if (!gPaths.batteryTechnologyPath)
326 LOGE("batteryTechnologyPath not found");
328 jclass clazz = env->FindClass("com/android/server/BatteryService");
331 LOGE("Can't find com/android/server/BatteryService");
335 gFieldIds.mAcOnline = env->GetFieldID(clazz, "mAcOnline", "Z");
336 gFieldIds.mUsbOnline = env->GetFieldID(clazz, "mUsbOnline", "Z");
337 gFieldIds.mBatteryStatus = env->GetFieldID(clazz, "mBatteryStatus", "I");
338 gFieldIds.mBatteryHealth = env->GetFieldID(clazz, "mBatteryHealth", "I");
339 gFieldIds.mBatteryPresent = env->GetFieldID(clazz, "mBatteryPresent", "Z");
340 gFieldIds.mBatteryLevel = env->GetFieldID(clazz, "mBatteryLevel", "I");
341 gFieldIds.mBatteryTechnology = env->GetFieldID(clazz, "mBatteryTechnology", "Ljava/lang/String;");
342 gFieldIds.mBatteryVoltage = env->GetFieldID(clazz, "mBatteryVoltage", "I");
343 gFieldIds.mBatteryTemperature = env->GetFieldID(clazz, "mBatteryTemperature", "I");
345 LOG_FATAL_IF(gFieldIds.mAcOnline == NULL, "Unable to find BatteryService.AC_ONLINE_PATH");
346 LOG_FATAL_IF(gFieldIds.mUsbOnline == NULL, "Unable to find BatteryService.USB_ONLINE_PATH");
347 LOG_FATAL_IF(gFieldIds.mBatteryStatus == NULL, "Unable to find BatteryService.BATTERY_STATUS_PATH");
348 LOG_FATAL_IF(gFieldIds.mBatteryHealth == NULL, "Unable to find BatteryService.BATTERY_HEALTH_PATH");
349 LOG_FATAL_IF(gFieldIds.mBatteryPresent == NULL, "Unable to find BatteryService.BATTERY_PRESENT_PATH");
350 LOG_FATAL_IF(gFieldIds.mBatteryLevel == NULL, "Unable to find BatteryService.BATTERY_CAPACITY_PATH");
351 LOG_FATAL_IF(gFieldIds.mBatteryVoltage == NULL, "Unable to find BatteryService.BATTERY_VOLTAGE_PATH");
352 LOG_FATAL_IF(gFieldIds.mBatteryTemperature == NULL, "Unable to find BatteryService.BATTERY_TEMPERATURE_PATH");
353 LOG_FATAL_IF(gFieldIds.mBatteryTechnology == NULL, "Unable to find BatteryService.BATTERY_TECHNOLOGY_PATH");
355 clazz = env->FindClass("android/os/BatteryManager");
358 LOGE("Can't find android/os/BatteryManager");
362 gConstants.statusUnknown = env->GetStaticIntField(clazz,
363 env->GetStaticFieldID(clazz, "BATTERY_STATUS_UNKNOWN", "I"));
365 gConstants.statusCharging = env->GetStaticIntField(clazz,
366 env->GetStaticFieldID(clazz, "BATTERY_STATUS_CHARGING", "I"));
368 gConstants.statusDischarging = env->GetStaticIntField(clazz,
369 env->GetStaticFieldID(clazz, "BATTERY_STATUS_DISCHARGING", "I"));
371 gConstants.statusNotCharging = env->GetStaticIntField(clazz,
372 env->GetStaticFieldID(clazz, "BATTERY_STATUS_NOT_CHARGING", "I"));
374 gConstants.statusFull = env->GetStaticIntField(clazz,
375 env->GetStaticFieldID(clazz, "BATTERY_STATUS_FULL", "I"));
377 gConstants.healthUnknown = env->GetStaticIntField(clazz,
378 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNKNOWN", "I"));
380 gConstants.healthGood = env->GetStaticIntField(clazz,
381 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_GOOD", "I"));
383 gConstants.healthOverheat = env->GetStaticIntField(clazz,
384 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_OVERHEAT", "I"));
386 gConstants.healthDead = env->GetStaticIntField(clazz,
387 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_DEAD", "I"));
389 gConstants.healthOverVoltage = env->GetStaticIntField(clazz,
390 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_OVER_VOLTAGE", "I"));
392 gConstants.healthUnspecifiedFailure = env->GetStaticIntField(clazz,
393 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNSPECIFIED_FAILURE", "I"));
395 gConstants.healthCold = env->GetStaticIntField(clazz,
396 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_COLD", "I"));
398 return jniRegisterNativeMethods(env, "com/android/server/BatteryService", sMethods, NELEM(sMethods));
401 } /* namespace android */