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