/**************************************************************************** * I.MX6 android BatteryService jni hacking * 声明: * 本文主要是为了知道Android的获取的电源管理的数据的jni是从Linux系统的 * 什么位置获取的,获取的机制是什么。 * * 2016-2-22 深圳 南山平山村 曾剑锋 ***************************************************************************/ /* * 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 <cutils/properties.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <dirent.h> #include <linux/ioctl.h> namespace android { /** * 从下面的路径可知,POWER_SUPPLY_PATH相当于电池管理初始路径。 * root@android:/sys/class/power_supply/bq274xx-0 # ls * capacity * capacity_level * charge_full * charge_full_design * charge_now * current_now * device * power * present * status * subsystem * technology * temp * type * uevent * voltage_now * root@android:/sys/class/power_supply/bq274xx-0 # */ #define POWER_SUPPLY_PATH "/sys/class/power_supply" /** * 为了在C/C++中表示属性和方法,JNI在jni.h头文件中定义了jfieldID和jmethodID类型来分别代表Java对象的属性和方法。我们在访问或是设置Java属性的时候,首先就要先在本地代码取得代表该Java属性的jfieldID,然后才能在本地代码进行Java属性操作。同样的,我们需要调用Java对象方法时,也是需要取得代表该方法的jmethodID才能进行Java方法调用。 */ struct FieldIds { // members jfieldID mAcOnline; jfieldID mUsbOnline; jfieldID mWirelessOnline; 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; jint healthCold; }; static BatteryManagerConstants gConstants; /** * 指向sysfs中电池对应的文件 */ struct PowerSupplyPaths { char* acOnlinePath; char* usbOnlinePath; char* wirelessOnlinePath; char* batteryStatusPath; char* batteryHealthPath; char* batteryPresentPath; char* batteryCapacityPath; char* batteryVoltagePath; char* batteryTemperaturePath; char* batteryTechnologyPath; }; static PowerSupplyPaths gPaths; static int gVoltageDivisor = 1; 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; // Full case 'N': return gConstants.statusNotCharging; // Not charging case 'U': return gConstants.statusUnknown; // Unknown default: { ALOGW("Unknown battery status '%s'", status); return gConstants.statusUnknown; } } } static jint getBatteryHealth(const char* status) { // 通过比较首字母来判断电池状态 switch (status[0]) { case 'C': return gConstants.healthCold; // Cold 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; } ALOGW("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: { ALOGW("Unknown battery health[2] '%s'", status); return gConstants.healthUnknown; } } } // 从文件中读取内容,并剔除最后的换行符 static int readFromFile(const char* path, char* buf, size_t size) { if (!path) return -1; int fd = open(path, O_RDONLY, 0); if (fd == -1) { ALOGE("Could not open '%s'", path); return -1; } ssize_t count = read(fd, buf, size); if (count > 0) { while (count > 0 && buf[count-1] == ' ') count--; buf[count] = '