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 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 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 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 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 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 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 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 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 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 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 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 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 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