/* * Copyright (C) 2014 Intel Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "ThermalManagerJNI" #include <nativehelper/JNIHelp.h> #include "jni.h" #include <utils/Log.h> #include <utils/misc.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <stdlib.h> #include <unistd.h> namespace android { #define THERMAL_ZONE_PATH "/sys/class/thermal/thermal_zone" #define COOLING_DEV_PATH "/sys/class/thermal/cooling_device" #define UNUSED(expr) (void)(expr) static int readFromFile(const char *path, char* buf, size_t size, bool throwError) { if (!path) return -1; int fd = open(path, O_RDONLY, 0); if (fd < 0) { if (throwError) { ALOGE("Could not open '%s'", path); } return -1; } ssize_t count = read(fd, buf, size); if (count > 0) { while (count > 0 && buf[count-1] == '\n') count--; buf[count] = '\0'; } else { buf[0] = '\0'; } close(fd); return count; } static int writeToFile(const char *path, int val) { const int SIZE = 20; int ret, fd, len; char value[SIZE]; if (!path) return -1; fd = open(path, O_WRONLY, 0); if (fd < 0) { ALOGE("writeToFile: Could not open '%s' err: %d", path, errno); return -1; } len = snprintf(value, SIZE, "%d\n", val); ret = write(fd, value, len); close(fd); return (ret == len) ? 0 : -1; } static int lookup(const char *base_path, const char *name) { const int SIZE = 128; char buf[SIZE]; char full_path[SIZE]; int count = 0; do { snprintf(full_path, SIZE, "%s%d/type", base_path, count); // Loop through all thermal_zones or cooling_devices until we // find a first match. We call it a match when the given // 'name' of the thermal_zone (or a cooling_device) matches // with the value of 'type' sysfs interface of a thermal_zone // (or cooling_device). if (readFromFile(full_path, buf, SIZE, false) < 0) break; if (!strcmp(name, buf)) return count; count++; } while(1); // lookup failed. return -1; } static int lookup_contains(const char *base_path, const char *name) { const int SIZE = 128; char buf[SIZE]; char full_path[SIZE]; int count = 0; do { snprintf(full_path, SIZE, "%s%d/type", base_path, count); if (readFromFile(full_path, buf, SIZE, false) < 0) break; // Check if 'buf' contains 'name' if (strstr(buf, name) != NULL) return count; count++; } while(1); // lookup failed. return -1; } static jboolean isFileExists(JNIEnv* env, jobject obj, jstring jPath) { const char *path = NULL; jboolean ret = true; UNUSED(obj); path = jPath ? env->GetStringUTFChars(jPath, NULL) : NULL; if (!path) { return false; } int fd = open(path, O_RDONLY, 0); if (fd < 0) { ret = false; } else { close(fd); } env->ReleaseStringUTFChars(jPath, path); return ret; } static jint getThermalZoneIndex(JNIEnv* env, jobject obj, jstring jType) { int ret; const char *type = NULL; UNUSED(obj); type = jType ? env->GetStringUTFChars(jType, NULL) : NULL; if (!type) { jniThrowNullPointerException(env, "Type"); return -1; } ret = lookup(THERMAL_ZONE_PATH, type); env->ReleaseStringUTFChars(jType, type); return ret; } static jint getThermalZoneIndexContains(JNIEnv* env, jobject obj, jstring jType) { int ret; const char *type = NULL; UNUSED(obj); type = jType ? env->GetStringUTFChars(jType, NULL) : NULL; if (!type) { jniThrowNullPointerException(env, "Type"); return -1; } ret = lookup_contains(THERMAL_ZONE_PATH, type); env->ReleaseStringUTFChars(jType, type); return ret; } static jint getCoolingDeviceIndex(JNIEnv* env, jobject obj, jstring jType) { int ret; const char *type = NULL; UNUSED(obj); type = jType ? env->GetStringUTFChars(jType, NULL) : NULL; if (!type) { jniThrowNullPointerException(env, "Type"); return -1; } ret = lookup(COOLING_DEV_PATH, type); env->ReleaseStringUTFChars(jType, type); return ret; } static jint getCoolingDeviceIndexContains(JNIEnv* env, jobject obj, jstring jType) { int ret; const char *type = NULL; UNUSED(obj); type = jType ? env->GetStringUTFChars(jType, NULL) : NULL; if (!type) { jniThrowNullPointerException(env, "Type"); return -1; } ret = lookup_contains(COOLING_DEV_PATH, type); env->ReleaseStringUTFChars(jType, type); return ret; } static jint writeSysfs(JNIEnv* env, jobject obj, jstring jPath, jint jVal) { int ret; const char *path = NULL; UNUSED(obj); path = jPath ? env->GetStringUTFChars(jPath, NULL) : NULL; if (!path) { jniThrowNullPointerException(env, "path"); return -EINVAL; } ret = writeToFile(path, jVal); env->ReleaseStringUTFChars(jPath, path); return ret; } static jstring readSysfs(JNIEnv* env, jobject obj, jstring jPath) { const char *path = NULL; const int SIZE = 512; char buf[SIZE]; UNUSED(obj); path = jPath ? env->GetStringUTFChars(jPath, NULL) : NULL; if (!path) { jniThrowNullPointerException(env, "path"); return NULL; } if (readFromFile(path, buf, SIZE, true) > 0) { env->ReleaseStringUTFChars(jPath, path); return env->NewStringUTF(buf); } else { env->ReleaseStringUTFChars(jPath, path); return NULL; } } static jint readSysfsTemp(JNIEnv* env, jobject obj, jstring jPath) { const char *path = NULL; const int SIZE = 64; char buf[SIZE]; // Convention: To allow returning of normal negative temperatures // (say -10C), let us return errno as a negative offset from // absolute zero millidegree C. const int ABS_ZERO = -273000; int ret; UNUSED(obj); path = jPath ? env->GetStringUTFChars(jPath, NULL) : NULL; if (!path) { jniThrowNullPointerException(env, "path"); return (ABS_ZERO - ENOENT); } ret = readFromFile(path, buf, SIZE, true); env->ReleaseStringUTFChars(jPath, path); if (ret > 0) { return atoi(buf); } return (ret + ABS_ZERO); } static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"native_readSysfs", "(Ljava/lang/String;)Ljava/lang/String;", (void*)readSysfs}, {"native_readSysfsTemp", "(Ljava/lang/String;)I", (void*)readSysfsTemp}, {"native_writeSysfs", "(Ljava/lang/String;I)I", (void*)writeSysfs}, {"native_getThermalZoneIndex", "(Ljava/lang/String;)I", (void*)getThermalZoneIndex}, {"native_getThermalZoneIndexContains", "(Ljava/lang/String;)I", (void*)getThermalZoneIndexContains}, {"native_getCoolingDeviceIndex", "(Ljava/lang/String;)I", (void*)getCoolingDeviceIndex}, {"native_getCoolingDeviceIndexContains", "(Ljava/lang/String;)I", (void*)getCoolingDeviceIndexContains}, {"native_isFileExists", "(Ljava/lang/String;)Z", (void*)isFileExists}, }; int register_intel_thermal_ituxd(JNIEnv* env) { jclass clazz = env->FindClass("com/intel/thermal/ThermalUtils"); if (clazz == NULL) { ALOGE("Can't find com/intel/thermal/ThermalUtils"); return -1; } return jniRegisterNativeMethods(env, "com/intel/thermal/ThermalUtils", sMethods, NELEM(sMethods)); } } /* namespace android */