com_android_server_BatteryService.cpp revision 5ad9fc2182116c083f5e59a347ef1b3e487861f7
1/* 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#include <dirent.h> 35#include <linux/ioctl.h> 36 37namespace android { 38 39#define POWER_SUPPLY_PATH "/sys/class/power_supply" 40 41struct FieldIds { 42 // members 43 jfieldID mAcOnline; 44 jfieldID mUsbOnline; 45 jfieldID mWirelessOnline; 46 jfieldID mBatteryStatus; 47 jfieldID mBatteryHealth; 48 jfieldID mBatteryPresent; 49 jfieldID mBatteryLevel; 50 jfieldID mBatteryVoltage; 51 jfieldID mBatteryTemperature; 52 jfieldID mBatteryTechnology; 53}; 54static FieldIds gFieldIds; 55 56struct BatteryManagerConstants { 57 jint statusUnknown; 58 jint statusCharging; 59 jint statusDischarging; 60 jint statusNotCharging; 61 jint statusFull; 62 jint healthUnknown; 63 jint healthGood; 64 jint healthOverheat; 65 jint healthDead; 66 jint healthOverVoltage; 67 jint healthUnspecifiedFailure; 68 jint healthCold; 69}; 70static BatteryManagerConstants gConstants; 71 72struct PowerSupplyPaths { 73 char* acOnlinePath; 74 char* usbOnlinePath; 75 char* wirelessOnlinePath; 76 char* batteryStatusPath; 77 char* batteryHealthPath; 78 char* batteryPresentPath; 79 char* batteryCapacityPath; 80 char* batteryVoltagePath; 81 char* batteryTemperaturePath; 82 char* batteryTechnologyPath; 83}; 84static PowerSupplyPaths gPaths; 85 86static int gVoltageDivisor = 1; 87 88static jint getBatteryStatus(const char* status) 89{ 90 switch (status[0]) { 91 case 'C': return gConstants.statusCharging; // Charging 92 case 'D': return gConstants.statusDischarging; // Discharging 93 case 'F': return gConstants.statusFull; // Full 94 case 'N': return gConstants.statusNotCharging; // Not charging 95 case 'U': return gConstants.statusUnknown; // Unknown 96 97 default: { 98 ALOGW("Unknown battery status '%s'", status); 99 return gConstants.statusUnknown; 100 } 101 } 102} 103 104static jint getBatteryHealth(const char* status) 105{ 106 switch (status[0]) { 107 case 'C': return gConstants.healthCold; // Cold 108 case 'D': return gConstants.healthDead; // Dead 109 case 'G': return gConstants.healthGood; // Good 110 case 'O': { 111 if (strcmp(status, "Overheat") == 0) { 112 return gConstants.healthOverheat; 113 } else if (strcmp(status, "Over voltage") == 0) { 114 return gConstants.healthOverVoltage; 115 } 116 ALOGW("Unknown battery health[1] '%s'", status); 117 return gConstants.healthUnknown; 118 } 119 120 case 'U': { 121 if (strcmp(status, "Unspecified failure") == 0) { 122 return gConstants.healthUnspecifiedFailure; 123 } else if (strcmp(status, "Unknown") == 0) { 124 return gConstants.healthUnknown; 125 } 126 // fall through 127 } 128 129 default: { 130 ALOGW("Unknown battery health[2] '%s'", status); 131 return gConstants.healthUnknown; 132 } 133 } 134} 135 136static int readFromFile(const char* path, char* buf, size_t size) 137{ 138 if (!path) 139 return -1; 140 int fd = open(path, O_RDONLY, 0); 141 if (fd == -1) { 142 ALOGE("Could not open '%s'", path); 143 return -1; 144 } 145 146 ssize_t count = read(fd, buf, size); 147 if (count > 0) { 148 while (count > 0 && buf[count-1] == '\n') 149 count--; 150 buf[count] = '\0'; 151 } else { 152 buf[0] = '\0'; 153 } 154 155 close(fd); 156 return count; 157} 158 159static void setBooleanField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID) 160{ 161 const int SIZE = 16; 162 char buf[SIZE]; 163 164 jboolean value = false; 165 if (readFromFile(path, buf, SIZE) > 0) { 166 if (buf[0] != '0') { 167 value = true; 168 } 169 } 170 env->SetBooleanField(obj, fieldID, value); 171} 172 173static void setIntField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID) 174{ 175 const int SIZE = 128; 176 char buf[SIZE]; 177 178 jint value = 0; 179 if (readFromFile(path, buf, SIZE) > 0) { 180 value = atoi(buf); 181 } 182 env->SetIntField(obj, fieldID, value); 183} 184 185static void setVoltageField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID) 186{ 187 const int SIZE = 128; 188 char buf[SIZE]; 189 190 jint value = 0; 191 if (readFromFile(path, buf, SIZE) > 0) { 192 value = atoi(buf); 193 value /= gVoltageDivisor; 194 } 195 env->SetIntField(obj, fieldID, value); 196} 197 198 199static void android_server_BatteryService_update(JNIEnv* env, jobject obj) 200{ 201 setBooleanField(env, obj, gPaths.acOnlinePath, gFieldIds.mAcOnline); 202 setBooleanField(env, obj, gPaths.usbOnlinePath, gFieldIds.mUsbOnline); 203 setBooleanField(env, obj, gPaths.wirelessOnlinePath, gFieldIds.mWirelessOnline); 204 setBooleanField(env, obj, gPaths.batteryPresentPath, gFieldIds.mBatteryPresent); 205 206 setIntField(env, obj, gPaths.batteryCapacityPath, gFieldIds.mBatteryLevel); 207 setVoltageField(env, obj, gPaths.batteryVoltagePath, gFieldIds.mBatteryVoltage); 208 setIntField(env, obj, gPaths.batteryTemperaturePath, gFieldIds.mBatteryTemperature); 209 210 const int SIZE = 128; 211 char buf[SIZE]; 212 213 if (readFromFile(gPaths.batteryStatusPath, buf, SIZE) > 0) 214 env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf)); 215 else 216 env->SetIntField(obj, gFieldIds.mBatteryStatus, 217 gConstants.statusUnknown); 218 219 if (readFromFile(gPaths.batteryHealthPath, buf, SIZE) > 0) 220 env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf)); 221 222 if (readFromFile(gPaths.batteryTechnologyPath, buf, SIZE) > 0) 223 env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf)); 224} 225 226static JNINativeMethod sMethods[] = { 227 /* name, signature, funcPtr */ 228 {"native_update", "()V", (void*)android_server_BatteryService_update}, 229}; 230 231int register_android_server_BatteryService(JNIEnv* env) 232{ 233 char path[PATH_MAX]; 234 struct dirent* entry; 235 236 DIR* dir = opendir(POWER_SUPPLY_PATH); 237 if (dir == NULL) { 238 ALOGE("Could not open %s\n", POWER_SUPPLY_PATH); 239 } else { 240 while ((entry = readdir(dir))) { 241 const char* name = entry->d_name; 242 243 // ignore "." and ".." 244 if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) { 245 continue; 246 } 247 248 char buf[20]; 249 // Look for "type" file in each subdirectory 250 snprintf(path, sizeof(path), "%s/%s/type", POWER_SUPPLY_PATH, name); 251 int length = readFromFile(path, buf, sizeof(buf)); 252 if (length > 0) { 253 if (buf[length - 1] == '\n') 254 buf[length - 1] = 0; 255 256 if (strcmp(buf, "Mains") == 0) { 257 snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name); 258 if (access(path, R_OK) == 0) 259 gPaths.acOnlinePath = strdup(path); 260 } 261 else if (strcmp(buf, "USB") == 0) { 262 snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name); 263 if (access(path, R_OK) == 0) 264 gPaths.usbOnlinePath = strdup(path); 265 } 266 else if (strcmp(buf, "Wireless") == 0) { 267 snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name); 268 if (access(path, R_OK) == 0) 269 gPaths.wirelessOnlinePath = strdup(path); 270 } 271 else if (strcmp(buf, "Battery") == 0) { 272 snprintf(path, sizeof(path), "%s/%s/status", POWER_SUPPLY_PATH, name); 273 if (access(path, R_OK) == 0) 274 gPaths.batteryStatusPath = strdup(path); 275 snprintf(path, sizeof(path), "%s/%s/health", POWER_SUPPLY_PATH, name); 276 if (access(path, R_OK) == 0) 277 gPaths.batteryHealthPath = strdup(path); 278 snprintf(path, sizeof(path), "%s/%s/present", POWER_SUPPLY_PATH, name); 279 if (access(path, R_OK) == 0) 280 gPaths.batteryPresentPath = strdup(path); 281 snprintf(path, sizeof(path), "%s/%s/capacity", POWER_SUPPLY_PATH, name); 282 if (access(path, R_OK) == 0) 283 gPaths.batteryCapacityPath = strdup(path); 284 285 snprintf(path, sizeof(path), "%s/%s/voltage_now", POWER_SUPPLY_PATH, name); 286 if (access(path, R_OK) == 0) { 287 gPaths.batteryVoltagePath = strdup(path); 288 // voltage_now is in microvolts, not millivolts 289 gVoltageDivisor = 1000; 290 } else { 291 snprintf(path, sizeof(path), "%s/%s/batt_vol", POWER_SUPPLY_PATH, name); 292 if (access(path, R_OK) == 0) 293 gPaths.batteryVoltagePath = strdup(path); 294 } 295 296 snprintf(path, sizeof(path), "%s/%s/temp", POWER_SUPPLY_PATH, name); 297 if (access(path, R_OK) == 0) { 298 gPaths.batteryTemperaturePath = strdup(path); 299 } else { 300 snprintf(path, sizeof(path), "%s/%s/batt_temp", POWER_SUPPLY_PATH, name); 301 if (access(path, R_OK) == 0) 302 gPaths.batteryTemperaturePath = strdup(path); 303 } 304 305 snprintf(path, sizeof(path), "%s/%s/technology", POWER_SUPPLY_PATH, name); 306 if (access(path, R_OK) == 0) 307 gPaths.batteryTechnologyPath = strdup(path); 308 } 309 } 310 } 311 closedir(dir); 312 } 313 314 if (!gPaths.acOnlinePath) 315 ALOGE("acOnlinePath not found"); 316 if (!gPaths.usbOnlinePath) 317 ALOGE("usbOnlinePath not found"); 318 if (!gPaths.wirelessOnlinePath) 319 ALOGE("wirelessOnlinePath not found"); 320 if (!gPaths.batteryStatusPath) 321 ALOGE("batteryStatusPath not found"); 322 if (!gPaths.batteryHealthPath) 323 ALOGE("batteryHealthPath not found"); 324 if (!gPaths.batteryPresentPath) 325 ALOGE("batteryPresentPath not found"); 326 if (!gPaths.batteryCapacityPath) 327 ALOGE("batteryCapacityPath not found"); 328 if (!gPaths.batteryVoltagePath) 329 ALOGE("batteryVoltagePath not found"); 330 if (!gPaths.batteryTemperaturePath) 331 ALOGE("batteryTemperaturePath not found"); 332 if (!gPaths.batteryTechnologyPath) 333 ALOGE("batteryTechnologyPath not found"); 334 335 jclass clazz = env->FindClass("com/android/server/BatteryService"); 336 337 if (clazz == NULL) { 338 ALOGE("Can't find com/android/server/BatteryService"); 339 return -1; 340 } 341 342 gFieldIds.mAcOnline = env->GetFieldID(clazz, "mAcOnline", "Z"); 343 gFieldIds.mUsbOnline = env->GetFieldID(clazz, "mUsbOnline", "Z"); 344 gFieldIds.mWirelessOnline = env->GetFieldID(clazz, "mWirelessOnline", "Z"); 345 gFieldIds.mBatteryStatus = env->GetFieldID(clazz, "mBatteryStatus", "I"); 346 gFieldIds.mBatteryHealth = env->GetFieldID(clazz, "mBatteryHealth", "I"); 347 gFieldIds.mBatteryPresent = env->GetFieldID(clazz, "mBatteryPresent", "Z"); 348 gFieldIds.mBatteryLevel = env->GetFieldID(clazz, "mBatteryLevel", "I"); 349 gFieldIds.mBatteryTechnology = env->GetFieldID(clazz, "mBatteryTechnology", "Ljava/lang/String;"); 350 gFieldIds.mBatteryVoltage = env->GetFieldID(clazz, "mBatteryVoltage", "I"); 351 gFieldIds.mBatteryTemperature = env->GetFieldID(clazz, "mBatteryTemperature", "I"); 352 353 LOG_FATAL_IF(gFieldIds.mAcOnline == NULL, "Unable to find BatteryService.AC_ONLINE_PATH"); 354 LOG_FATAL_IF(gFieldIds.mUsbOnline == NULL, "Unable to find BatteryService.USB_ONLINE_PATH"); 355 LOG_FATAL_IF(gFieldIds.mWirelessOnline == NULL, "Unable to find BatteryService.WIRELESS_ONLINE_PATH"); 356 LOG_FATAL_IF(gFieldIds.mBatteryStatus == NULL, "Unable to find BatteryService.BATTERY_STATUS_PATH"); 357 LOG_FATAL_IF(gFieldIds.mBatteryHealth == NULL, "Unable to find BatteryService.BATTERY_HEALTH_PATH"); 358 LOG_FATAL_IF(gFieldIds.mBatteryPresent == NULL, "Unable to find BatteryService.BATTERY_PRESENT_PATH"); 359 LOG_FATAL_IF(gFieldIds.mBatteryLevel == NULL, "Unable to find BatteryService.BATTERY_CAPACITY_PATH"); 360 LOG_FATAL_IF(gFieldIds.mBatteryVoltage == NULL, "Unable to find BatteryService.BATTERY_VOLTAGE_PATH"); 361 LOG_FATAL_IF(gFieldIds.mBatteryTemperature == NULL, "Unable to find BatteryService.BATTERY_TEMPERATURE_PATH"); 362 LOG_FATAL_IF(gFieldIds.mBatteryTechnology == NULL, "Unable to find BatteryService.BATTERY_TECHNOLOGY_PATH"); 363 364 clazz = env->FindClass("android/os/BatteryManager"); 365 366 if (clazz == NULL) { 367 ALOGE("Can't find android/os/BatteryManager"); 368 return -1; 369 } 370 371 gConstants.statusUnknown = env->GetStaticIntField(clazz, 372 env->GetStaticFieldID(clazz, "BATTERY_STATUS_UNKNOWN", "I")); 373 374 gConstants.statusCharging = env->GetStaticIntField(clazz, 375 env->GetStaticFieldID(clazz, "BATTERY_STATUS_CHARGING", "I")); 376 377 gConstants.statusDischarging = env->GetStaticIntField(clazz, 378 env->GetStaticFieldID(clazz, "BATTERY_STATUS_DISCHARGING", "I")); 379 380 gConstants.statusNotCharging = env->GetStaticIntField(clazz, 381 env->GetStaticFieldID(clazz, "BATTERY_STATUS_NOT_CHARGING", "I")); 382 383 gConstants.statusFull = env->GetStaticIntField(clazz, 384 env->GetStaticFieldID(clazz, "BATTERY_STATUS_FULL", "I")); 385 386 gConstants.healthUnknown = env->GetStaticIntField(clazz, 387 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNKNOWN", "I")); 388 389 gConstants.healthGood = env->GetStaticIntField(clazz, 390 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_GOOD", "I")); 391 392 gConstants.healthOverheat = env->GetStaticIntField(clazz, 393 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_OVERHEAT", "I")); 394 395 gConstants.healthDead = env->GetStaticIntField(clazz, 396 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_DEAD", "I")); 397 398 gConstants.healthOverVoltage = env->GetStaticIntField(clazz, 399 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_OVER_VOLTAGE", "I")); 400 401 gConstants.healthUnspecifiedFailure = env->GetStaticIntField(clazz, 402 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNSPECIFIED_FAILURE", "I")); 403 404 gConstants.healthCold = env->GetStaticIntField(clazz, 405 env->GetStaticFieldID(clazz, "BATTERY_HEALTH_COLD", "I")); 406 407 return jniRegisterNativeMethods(env, "com/android/server/BatteryService", sMethods, NELEM(sMethods)); 408} 409 410} /* namespace android */ 411