Merge "BatteryService: Allow power supplies to switch type between AC and USB"

This commit is contained in:
Todd Poynor
2013-01-30 23:18:39 +00:00
committed by Android (Google) Code Review

View File

@@ -33,6 +33,8 @@
#include <unistd.h>
#include <dirent.h>
#include <linux/ioctl.h>
#include <utils/Vector.h>
#include <utils/String8.h>
namespace android {
@@ -70,21 +72,28 @@ struct BatteryManagerConstants {
static BatteryManagerConstants gConstants;
struct PowerSupplyPaths {
char* acOnlinePath;
char* usbOnlinePath;
char* wirelessOnlinePath;
char* batteryStatusPath;
char* batteryHealthPath;
char* batteryPresentPath;
char* batteryCapacityPath;
char* batteryVoltagePath;
char* batteryTemperaturePath;
char* batteryTechnologyPath;
String8 batteryStatusPath;
String8 batteryHealthPath;
String8 batteryPresentPath;
String8 batteryCapacityPath;
String8 batteryVoltagePath;
String8 batteryTemperaturePath;
String8 batteryTechnologyPath;
};
static PowerSupplyPaths gPaths;
static Vector<String8> gChargerNames;
static int gVoltageDivisor = 1;
enum PowerSupplyType {
ANDROID_POWER_SUPPLY_TYPE_UNKNOWN = 0,
ANDROID_POWER_SUPPLY_TYPE_AC,
ANDROID_POWER_SUPPLY_TYPE_USB,
ANDROID_POWER_SUPPLY_TYPE_WIRELESS,
ANDROID_POWER_SUPPLY_TYPE_BATTERY
};
static jint getBatteryStatus(const char* status)
{
switch (status[0]) {
@@ -133,13 +142,13 @@ static jint getBatteryHealth(const char* status)
}
}
static int readFromFile(const char* path, char* buf, size_t size)
static int readFromFile(const String8& path, char* buf, size_t size)
{
if (!path)
return -1;
int fd = open(path, O_RDONLY, 0);
int fd = open(path.string(), O_RDONLY, 0);
if (fd == -1) {
ALOGE("Could not open '%s'", path);
ALOGE("Could not open '%s'", path.string());
return -1;
}
@@ -156,7 +165,7 @@ static int readFromFile(const char* path, char* buf, size_t size)
return count;
}
static void setBooleanField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
static void setBooleanField(JNIEnv* env, jobject obj, const String8& path, jfieldID fieldID)
{
const int SIZE = 16;
char buf[SIZE];
@@ -170,7 +179,7 @@ static void setBooleanField(JNIEnv* env, jobject obj, const char* path, jfieldID
env->SetBooleanField(obj, fieldID, value);
}
static void setIntField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
static void setIntField(JNIEnv* env, jobject obj, const String8& path, jfieldID fieldID)
{
const int SIZE = 128;
char buf[SIZE];
@@ -182,7 +191,7 @@ static void setIntField(JNIEnv* env, jobject obj, const char* path, jfieldID fie
env->SetIntField(obj, fieldID, value);
}
static void setVoltageField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
static void setVoltageField(JNIEnv* env, jobject obj, const String8& path, jfieldID fieldID)
{
const int SIZE = 128;
char buf[SIZE];
@@ -195,12 +204,29 @@ static void setVoltageField(JNIEnv* env, jobject obj, const char* path, jfieldID
env->SetIntField(obj, fieldID, value);
}
static PowerSupplyType readPowerSupplyType(const String8& path) {
const int SIZE = 128;
char buf[SIZE];
int length = readFromFile(path, buf, SIZE);
if (length <= 0)
return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
if (buf[length - 1] == '\n')
buf[length - 1] = 0;
if (strcmp(buf, "Battery") == 0)
return ANDROID_POWER_SUPPLY_TYPE_BATTERY;
else if (strcmp(buf, "Mains") == 0)
return ANDROID_POWER_SUPPLY_TYPE_AC;
else if (strcmp(buf, "USB") == 0)
return ANDROID_POWER_SUPPLY_TYPE_USB;
else if (strcmp(buf, "Wireless") == 0)
return ANDROID_POWER_SUPPLY_TYPE_WIRELESS;
else
return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
}
static void android_server_BatteryService_update(JNIEnv* env, jobject obj)
{
setBooleanField(env, obj, gPaths.acOnlinePath, gFieldIds.mAcOnline);
setBooleanField(env, obj, gPaths.usbOnlinePath, gFieldIds.mUsbOnline);
setBooleanField(env, obj, gPaths.wirelessOnlinePath, gFieldIds.mWirelessOnline);
setBooleanField(env, obj, gPaths.batteryPresentPath, gFieldIds.mBatteryPresent);
setIntField(env, obj, gPaths.batteryCapacityPath, gFieldIds.mBatteryLevel);
@@ -221,16 +247,54 @@ static void android_server_BatteryService_update(JNIEnv* env, jobject obj)
if (readFromFile(gPaths.batteryTechnologyPath, buf, SIZE) > 0)
env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf));
unsigned int i;
String8 path;
jboolean acOnline = false;
jboolean usbOnline = false;
jboolean wirelessOnline = false;
for (i = 0; i < gChargerNames.size(); i++) {
path.clear();
path.appendFormat("%s/%s/online", POWER_SUPPLY_PATH,
gChargerNames[i].string());
if (readFromFile(path, buf, SIZE) > 0) {
if (buf[0] != '0') {
path.clear();
path.appendFormat("%s/%s/type", POWER_SUPPLY_PATH,
gChargerNames[i].string());
switch(readPowerSupplyType(path)) {
case ANDROID_POWER_SUPPLY_TYPE_AC:
acOnline = true;
break;
case ANDROID_POWER_SUPPLY_TYPE_USB:
usbOnline = true;
break;
case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
wirelessOnline = true;
break;
default:
ALOGW("%s: Unknown power supply type",
gChargerNames[i].string());
}
}
}
}
env->SetBooleanField(obj, gFieldIds.mAcOnline, acOnline);
env->SetBooleanField(obj, gFieldIds.mUsbOnline, usbOnline);
env->SetBooleanField(obj, gFieldIds.mWirelessOnline, wirelessOnline);
}
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"native_update", "()V", (void*)android_server_BatteryService_update},
{"native_update", "()V", (void*)android_server_BatteryService_update},
};
int register_android_server_BatteryService(JNIEnv* env)
{
char path[PATH_MAX];
String8 path;
struct dirent* entry;
DIR* dir = opendir(POWER_SUPPLY_PATH);
@@ -247,76 +311,72 @@ int register_android_server_BatteryService(JNIEnv* env)
char buf[20];
// Look for "type" file in each subdirectory
snprintf(path, sizeof(path), "%s/%s/type", POWER_SUPPLY_PATH, name);
int length = readFromFile(path, buf, sizeof(buf));
if (length > 0) {
if (buf[length - 1] == '\n')
buf[length - 1] = 0;
path.clear();
path.appendFormat("%s/%s/type", POWER_SUPPLY_PATH, name);
switch(readPowerSupplyType(path)) {
case ANDROID_POWER_SUPPLY_TYPE_AC:
case ANDROID_POWER_SUPPLY_TYPE_USB:
case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
path.clear();
path.appendFormat("%s/%s/online", POWER_SUPPLY_PATH, name);
if (access(path.string(), R_OK) == 0)
gChargerNames.add(String8(name));
break;
if (strcmp(buf, "Mains") == 0) {
snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
gPaths.acOnlinePath = strdup(path);
}
else if (strcmp(buf, "USB") == 0) {
snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
gPaths.usbOnlinePath = strdup(path);
}
else if (strcmp(buf, "Wireless") == 0) {
snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
gPaths.wirelessOnlinePath = strdup(path);
}
else if (strcmp(buf, "Battery") == 0) {
snprintf(path, sizeof(path), "%s/%s/status", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
gPaths.batteryStatusPath = strdup(path);
snprintf(path, sizeof(path), "%s/%s/health", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
gPaths.batteryHealthPath = strdup(path);
snprintf(path, sizeof(path), "%s/%s/present", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
gPaths.batteryPresentPath = strdup(path);
snprintf(path, sizeof(path), "%s/%s/capacity", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
gPaths.batteryCapacityPath = strdup(path);
case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
path.clear();
path.appendFormat("%s/%s/status", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
gPaths.batteryStatusPath = path;
path.clear();
path.appendFormat("%s/%s/health", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
gPaths.batteryHealthPath = path;
path.clear();
path.appendFormat("%s/%s/present", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
gPaths.batteryPresentPath = path;
path.clear();
path.appendFormat("%s/%s/capacity", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
gPaths.batteryCapacityPath = path;
snprintf(path, sizeof(path), "%s/%s/voltage_now", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0) {
gPaths.batteryVoltagePath = strdup(path);
// voltage_now is in microvolts, not millivolts
gVoltageDivisor = 1000;
} else {
snprintf(path, sizeof(path), "%s/%s/batt_vol", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
gPaths.batteryVoltagePath = strdup(path);
}
snprintf(path, sizeof(path), "%s/%s/temp", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0) {
gPaths.batteryTemperaturePath = strdup(path);
} else {
snprintf(path, sizeof(path), "%s/%s/batt_temp", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
gPaths.batteryTemperaturePath = strdup(path);
}
snprintf(path, sizeof(path), "%s/%s/technology", POWER_SUPPLY_PATH, name);
path.clear();
path.appendFormat("%s/%s/voltage_now", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0) {
gPaths.batteryVoltagePath = path;
// voltage_now is in microvolts, not millivolts
gVoltageDivisor = 1000;
} else {
path.clear();
path.appendFormat("%s/%s/batt_vol", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
gPaths.batteryTechnologyPath = strdup(path);
gPaths.batteryVoltagePath = path;
}
path.clear();
path.appendFormat("%s/%s/temp", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0) {
gPaths.batteryTemperaturePath = path;
} else {
path.clear();
path.appendFormat("%s/%s/batt_temp", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
gPaths.batteryTemperaturePath = path;
}
path.clear();
path.appendFormat("%s/%s/technology", POWER_SUPPLY_PATH, name);
if (access(path, R_OK) == 0)
gPaths.batteryTechnologyPath = path;
break;
}
}
closedir(dir);
}
if (!gPaths.acOnlinePath)
ALOGE("acOnlinePath not found");
if (!gPaths.usbOnlinePath)
ALOGE("usbOnlinePath not found");
if (!gPaths.wirelessOnlinePath)
ALOGE("wirelessOnlinePath not found");
if (!gChargerNames.size())
ALOGE("No charger supplies found");
if (!gPaths.batteryStatusPath)
ALOGE("batteryStatusPath not found");
if (!gPaths.batteryHealthPath)