1 /*
2 * Copyright (C) 2014 Intel Corporation
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 "ThermalManagerJNI"
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 <stdlib.h>
29 #include <unistd.h>
30
31 namespace android {
32
33 #define THERMAL_ZONE_PATH "/sys/class/thermal/thermal_zone"
34 #define COOLING_DEV_PATH "/sys/class/thermal/cooling_device"
35
readFromFile(const char * path,char * buf,size_t size,bool throwError)36 static int readFromFile(const char *path, char* buf, size_t size, bool throwError)
37 {
38 if (!path)
39 return -1;
40
41 int fd = open(path, O_RDONLY, 0);
42 if (fd < 0) {
43 if (throwError) {
44 ALOGE("Could not open '%s'", path);
45 }
46 return -1;
47 }
48
49 ssize_t count = read(fd, buf, size);
50 if (count > 0) {
51 while (count > 0 && buf[count-1] == '\n')
52 count--;
53 buf[count] = '\0';
54 } else {
55 buf[0] = '\0';
56 }
57
58 close(fd);
59 return count;
60 }
61
writeToFile(const char * path,int val)62 static int writeToFile(const char *path, int val)
63 {
64 const int SIZE = 20;
65 int ret, fd, len;
66 char value[SIZE];
67
68 if (!path)
69 return -1;
70
71 fd = open(path, O_WRONLY, 0);
72 if (fd < 0) {
73 ALOGE("writeToFile: Could not open '%s' err: %d", path, errno);
74 return -1;
75 }
76
77 len = snprintf(value, SIZE, "%d\n", val);
78 ret = write(fd, value, len);
79
80 close(fd);
81 return (ret == len) ? 0 : -1;
82 }
83
lookup(const char * base_path,const char * name)84 static int lookup(const char *base_path, const char *name)
85 {
86 const int SIZE = 128;
87 char buf[SIZE];
88 char full_path[SIZE];
89 int count = 0;
90
91 do {
92 snprintf(full_path, SIZE, "%s%d/type", base_path, count);
93 // Loop through all thermal_zones or cooling_devices until we
94 // find a first match. We call it a match when the given
95 // 'name' of the thermal_zone (or a cooling_device) matches
96 // with the value of 'type' sysfs interface of a thermal_zone
97 // (or cooling_device).
98 if (readFromFile(full_path, buf, SIZE, false) < 0) break;
99
100 if (!strcmp(name, buf)) return count;
101
102 count++;
103 } while(1);
104
105 // lookup failed.
106 return -1;
107 }
108
lookup_contains(const char * base_path,const char * name)109 static int lookup_contains(const char *base_path, const char *name)
110 {
111 const int SIZE = 128;
112 char buf[SIZE];
113 char full_path[SIZE];
114 int count = 0;
115
116 do {
117 snprintf(full_path, SIZE, "%s%d/type", base_path, count);
118 if (readFromFile(full_path, buf, SIZE, false) < 0) break;
119 // Check if 'buf' contains 'name'
120 if (strstr(buf, name) != NULL) return count;
121
122 count++;
123 } while(1);
124
125 // lookup failed.
126 return -1;
127 }
128
isFileExists(JNIEnv * env,jobject obj,jstring jPath)129 static jboolean isFileExists(JNIEnv* env, jobject obj, jstring jPath)
130 {
131 const char *path = NULL;
132 jboolean ret = true;
133
134 path = jPath ? env->GetStringUTFChars(jPath, NULL) : NULL;
135 if (!path) {
136 return false;
137 }
138
139 int fd = open(path, O_RDONLY, 0);
140
141 if (fd < 0) {
142 ret = false;
143 } else {
144 close(fd);
145 }
146 env->ReleaseStringUTFChars(jPath, path);
147 return ret;
148 }
149
getThermalZoneIndex(JNIEnv * env,jobject obj,jstring jType)150 static jint getThermalZoneIndex(JNIEnv* env, jobject obj, jstring jType)
151 {
152 int ret;
153 const char *type = NULL;
154
155 type = jType ? env->GetStringUTFChars(jType, NULL) : NULL;
156 if (!type) {
157 jniThrowNullPointerException(env, "Type");
158 return -1;
159 }
160
161 ret = lookup(THERMAL_ZONE_PATH, type);
162 env->ReleaseStringUTFChars(jType, type);
163 return ret;
164 }
165
getThermalZoneIndexContains(JNIEnv * env,jobject obj,jstring jType)166 static jint getThermalZoneIndexContains(JNIEnv* env, jobject obj, jstring jType)
167 {
168 int ret;
169 const char *type = NULL;
170
171 type = jType ? env->GetStringUTFChars(jType, NULL) : NULL;
172 if (!type) {
173 jniThrowNullPointerException(env, "Type");
174 return -1;
175 }
176
177 ret = lookup_contains(THERMAL_ZONE_PATH, type);
178 env->ReleaseStringUTFChars(jType, type);
179 return ret;
180 }
181
getCoolingDeviceIndex(JNIEnv * env,jobject obj,jstring jType)182 static jint getCoolingDeviceIndex(JNIEnv* env, jobject obj, jstring jType)
183 {
184 int ret;
185 const char *type = NULL;
186
187 type = jType ? env->GetStringUTFChars(jType, NULL) : NULL;
188 if (!type) {
189 jniThrowNullPointerException(env, "Type");
190 return -1;
191 }
192
193 ret = lookup(COOLING_DEV_PATH, type);
194 env->ReleaseStringUTFChars(jType, type);
195 return ret;
196 }
197
getCoolingDeviceIndexContains(JNIEnv * env,jobject obj,jstring jType)198 static jint getCoolingDeviceIndexContains(JNIEnv* env, jobject obj, jstring jType)
199 {
200 int ret;
201 const char *type = NULL;
202
203 type = jType ? env->GetStringUTFChars(jType, NULL) : NULL;
204 if (!type) {
205 jniThrowNullPointerException(env, "Type");
206 return -1;
207 }
208
209 ret = lookup_contains(COOLING_DEV_PATH, type);
210 env->ReleaseStringUTFChars(jType, type);
211 return ret;
212 }
213
writeSysfs(JNIEnv * env,jobject obj,jstring jPath,jint jVal)214 static jint writeSysfs(JNIEnv* env, jobject obj, jstring jPath, jint jVal)
215 {
216 int ret;
217 const char *path = NULL;
218
219 path = jPath ? env->GetStringUTFChars(jPath, NULL) : NULL;
220 if (!path) {
221 jniThrowNullPointerException(env, "path");
222 return -EINVAL;
223 }
224
225 ret = writeToFile(path, jVal);
226 env->ReleaseStringUTFChars(jPath, path);
227 return ret;
228 }
229
readSysfs(JNIEnv * env,jobject obj,jstring jPath)230 static jstring readSysfs(JNIEnv* env, jobject obj, jstring jPath)
231 {
232 const char *path = NULL;
233 const int SIZE = 512;
234 char buf[SIZE];
235
236 path = jPath ? env->GetStringUTFChars(jPath, NULL) : NULL;
237 if (!path) {
238 jniThrowNullPointerException(env, "path");
239 return NULL;
240 }
241
242 if (readFromFile(path, buf, SIZE, true) > 0) {
243 env->ReleaseStringUTFChars(jPath, path);
244 return env->NewStringUTF(buf);
245 } else {
246 env->ReleaseStringUTFChars(jPath, path);
247 return NULL;
248 }
249 }
250
readSysfsTemp(JNIEnv * env,jobject obj,jstring jPath)251 static jint readSysfsTemp(JNIEnv* env, jobject obj, jstring jPath)
252 {
253 const char *path = NULL;
254 const int SIZE = 64;
255 char buf[SIZE];
256 // Convention: To allow returning of normal negative temperatures
257 // (say -10C), let us return errno as a negative offset from
258 // absolute zero millidegree C.
259 const int ABS_ZERO = -273000;
260 int ret;
261
262 path = jPath ? env->GetStringUTFChars(jPath, NULL) : NULL;
263 if (!path) {
264 jniThrowNullPointerException(env, "path");
265 return (ABS_ZERO - ENOENT);
266 }
267
268 ret = readFromFile(path, buf, SIZE, true);
269 env->ReleaseStringUTFChars(jPath, path);
270 if (ret > 0) {
271 return atoi(buf);
272 }
273 return (ret + ABS_ZERO);
274 }
275
276 static JNINativeMethod sMethods[] = {
277 /* name, signature, funcPtr */
278 {"native_readSysfs", "(Ljava/lang/String;)Ljava/lang/String;", (void*)readSysfs},
279 {"native_readSysfsTemp", "(Ljava/lang/String;)I", (void*)readSysfsTemp},
280 {"native_writeSysfs", "(Ljava/lang/String;I)I", (void*)writeSysfs},
281 {"native_getThermalZoneIndex", "(Ljava/lang/String;)I", (void*)getThermalZoneIndex},
282 {"native_getThermalZoneIndexContains", "(Ljava/lang/String;)I",
283 (void*)getThermalZoneIndexContains},
284 {"native_getCoolingDeviceIndex", "(Ljava/lang/String;)I", (void*)getCoolingDeviceIndex},
285 {"native_getCoolingDeviceIndexContains", "(Ljava/lang/String;)I",
286 (void*)getCoolingDeviceIndexContains},
287 {"native_isFileExists", "(Ljava/lang/String;)Z", (void*)isFileExists},
288 };
289
register_intel_thermal_ituxd(JNIEnv * env)290 int register_intel_thermal_ituxd(JNIEnv* env)
291 {
292 jclass clazz = env->FindClass("com/intel/thermal/ThermalUtils");
293 if (clazz == NULL) {
294 ALOGE("Can't find com/intel/thermal/ThermalUtils");
295 return -1;
296 }
297
298 return jniRegisterNativeMethods(env, "com/intel/thermal/ThermalUtils",
299 sMethods, NELEM(sMethods));
300 }
301
302 } /* namespace android */
303