/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "BatteryService" #include "JNIHelp.h" #include "jni.h" #include "utils/Log.h" #include "utils/misc.h" #include #include #include #include #include #include #include #include #include #include #if HAVE_ANDROID_OS #include #endif namespace android { #define AC_ONLINE_PATH "/sys/class/power_supply/ac/online" #define USB_ONLINE_PATH "/sys/class/power_supply/usb/online" #define BATTERY_STATUS_PATH "/sys/class/power_supply/battery/status" #define BATTERY_HEALTH_PATH "/sys/class/power_supply/battery/health" #define BATTERY_PRESENT_PATH "/sys/class/power_supply/battery/present" #define BATTERY_CAPACITY_PATH "/sys/class/power_supply/battery/capacity" #define BATTERY_VOLTAGE_PATH "/sys/class/power_supply/battery/batt_vol" #define BATTERY_TEMPERATURE_PATH "/sys/class/power_supply/battery/batt_temp" #define BATTERY_TECHNOLOGY_PATH "/sys/class/power_supply/battery/technology" struct FieldIds { // members jfieldID mAcOnline; jfieldID mUsbOnline; jfieldID mBatteryStatus; jfieldID mBatteryHealth; jfieldID mBatteryPresent; jfieldID mBatteryLevel; jfieldID mBatteryVoltage; jfieldID mBatteryTemperature; jfieldID mBatteryTechnology; }; static FieldIds gFieldIds; struct BatteryManagerConstants { jint statusUnknown; jint statusCharging; jint statusDischarging; jint statusNotCharging; jint statusFull; jint healthUnknown; jint healthGood; jint healthOverheat; jint healthDead; jint healthOverVoltage; jint healthUnspecifiedFailure; }; static BatteryManagerConstants gConstants; static jint getBatteryStatus(const char* status) { switch (status[0]) { case 'C': return gConstants.statusCharging; // Charging case 'D': return gConstants.statusDischarging; // Discharging case 'F': return gConstants.statusFull; // Not charging case 'N': return gConstants.statusNotCharging; // Full case 'U': return gConstants.statusUnknown; // Unknown default: { LOGW("Unknown battery status '%s'", status); return gConstants.statusUnknown; } } } static jint getBatteryHealth(const char* status) { switch (status[0]) { case 'D': return gConstants.healthDead; // Dead case 'G': return gConstants.healthGood; // Good case 'O': { if (strcmp(status, "Overheat") == 0) { return gConstants.healthOverheat; } else if (strcmp(status, "Over voltage") == 0) { return gConstants.healthOverVoltage; } LOGW("Unknown battery health[1] '%s'", status); return gConstants.healthUnknown; } case 'U': { if (strcmp(status, "Unspecified failure") == 0) { return gConstants.healthUnspecifiedFailure; } else if (strcmp(status, "Unknown") == 0) { return gConstants.healthUnknown; } // fall through } default: { LOGW("Unknown battery health[2] '%s'", status); return gConstants.healthUnknown; } } } static int readFromFile(const char* path, char* buf, size_t size) { int fd = open(path, O_RDONLY, 0); if (fd == -1) { LOGE("Could not open '%s'", path); return -1; } size_t count = read(fd, buf, size); if (count > 0) { count = (count < size) ? count : size - 1; while (count > 0 && buf[count-1] == '\n') count--; buf[count] = '\0'; } else { buf[0] = '\0'; } close(fd); return count; } static void setBooleanField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID) { const int SIZE = 16; char buf[SIZE]; jboolean value = false; if (readFromFile(path, buf, SIZE) > 0) { if (buf[0] == '1') { value = true; } } env->SetBooleanField(obj, fieldID, value); } static void setIntField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID) { const int SIZE = 128; char buf[SIZE]; jint value = 0; if (readFromFile(path, buf, SIZE) > 0) { value = atoi(buf); } env->SetIntField(obj, fieldID, value); } static void android_server_BatteryService_update(JNIEnv* env, jobject obj) { setBooleanField(env, obj, AC_ONLINE_PATH, gFieldIds.mAcOnline); setBooleanField(env, obj, USB_ONLINE_PATH, gFieldIds.mUsbOnline); setBooleanField(env, obj, BATTERY_PRESENT_PATH, gFieldIds.mBatteryPresent); setIntField(env, obj, BATTERY_CAPACITY_PATH, gFieldIds.mBatteryLevel); setIntField(env, obj, BATTERY_VOLTAGE_PATH, gFieldIds.mBatteryVoltage); setIntField(env, obj, BATTERY_TEMPERATURE_PATH, gFieldIds.mBatteryTemperature); const int SIZE = 128; char buf[SIZE]; if (readFromFile(BATTERY_STATUS_PATH, buf, SIZE) > 0) env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf)); if (readFromFile(BATTERY_HEALTH_PATH, buf, SIZE) > 0) env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf)); if (readFromFile(BATTERY_TECHNOLOGY_PATH, buf, SIZE) > 0) env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf)); } static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"native_update", "()V", (void*)android_server_BatteryService_update}, }; int register_android_server_BatteryService(JNIEnv* env) { jclass clazz = env->FindClass("com/android/server/BatteryService"); if (clazz == NULL) { LOGE("Can't find com/android/server/BatteryService"); return -1; } gFieldIds.mAcOnline = env->GetFieldID(clazz, "mAcOnline", "Z"); gFieldIds.mUsbOnline = env->GetFieldID(clazz, "mUsbOnline", "Z"); gFieldIds.mBatteryStatus = env->GetFieldID(clazz, "mBatteryStatus", "I"); gFieldIds.mBatteryHealth = env->GetFieldID(clazz, "mBatteryHealth", "I"); gFieldIds.mBatteryPresent = env->GetFieldID(clazz, "mBatteryPresent", "Z"); gFieldIds.mBatteryLevel = env->GetFieldID(clazz, "mBatteryLevel", "I"); gFieldIds.mBatteryTechnology = env->GetFieldID(clazz, "mBatteryTechnology", "Ljava/lang/String;"); gFieldIds.mBatteryVoltage = env->GetFieldID(clazz, "mBatteryVoltage", "I"); gFieldIds.mBatteryTemperature = env->GetFieldID(clazz, "mBatteryTemperature", "I"); LOG_FATAL_IF(gFieldIds.mAcOnline == NULL, "Unable to find BatteryService.AC_ONLINE_PATH"); LOG_FATAL_IF(gFieldIds.mUsbOnline == NULL, "Unable to find BatteryService.USB_ONLINE_PATH"); LOG_FATAL_IF(gFieldIds.mBatteryStatus == NULL, "Unable to find BatteryService.BATTERY_STATUS_PATH"); LOG_FATAL_IF(gFieldIds.mBatteryHealth == NULL, "Unable to find BatteryService.BATTERY_HEALTH_PATH"); LOG_FATAL_IF(gFieldIds.mBatteryPresent == NULL, "Unable to find BatteryService.BATTERY_PRESENT_PATH"); LOG_FATAL_IF(gFieldIds.mBatteryLevel == NULL, "Unable to find BatteryService.BATTERY_CAPACITY_PATH"); LOG_FATAL_IF(gFieldIds.mBatteryVoltage == NULL, "Unable to find BatteryService.BATTERY_VOLTAGE_PATH"); LOG_FATAL_IF(gFieldIds.mBatteryTemperature == NULL, "Unable to find BatteryService.BATTERY_TEMPERATURE_PATH"); LOG_FATAL_IF(gFieldIds.mBatteryTechnology == NULL, "Unable to find BatteryService.BATTERY_TECHNOLOGY_PATH"); clazz = env->FindClass("android/os/BatteryManager"); if (clazz == NULL) { LOGE("Can't find android/os/BatteryManager"); return -1; } gConstants.statusUnknown = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "BATTERY_STATUS_UNKNOWN", "I")); gConstants.statusCharging = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "BATTERY_STATUS_CHARGING", "I")); gConstants.statusDischarging = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "BATTERY_STATUS_DISCHARGING", "I")); gConstants.statusNotCharging = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "BATTERY_STATUS_NOT_CHARGING", "I")); gConstants.statusFull = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "BATTERY_STATUS_FULL", "I")); gConstants.healthUnknown = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNKNOWN", "I")); gConstants.healthGood = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "BATTERY_HEALTH_GOOD", "I")); gConstants.healthOverheat = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "BATTERY_HEALTH_OVERHEAT", "I")); gConstants.healthDead = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "BATTERY_HEALTH_DEAD", "I")); gConstants.healthOverVoltage = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "BATTERY_HEALTH_OVER_VOLTAGE", "I")); gConstants.healthUnspecifiedFailure = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNSPECIFIED_FAILURE", "I")); return jniRegisterNativeMethods(env, "com/android/server/BatteryService", sMethods, NELEM(sMethods)); } } /* namespace android */