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