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 31namespace 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 38static 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 64static 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 86static 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 111static 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 131static 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 153static 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 170static 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 187static 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 204static 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 221static 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 238static 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 260static 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 286static 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 300int 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