OSDN Git Service

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