EM/THERMAL: Enabling thermal service.
Enabling Android thermal service feature to control
platform and skin temprature.
Bug: 17154068
BZ: 217020
Change-Id: Ife465076323e126d9cb66653b1313cffc4b963c1
Signed-off-by: shravan <[email protected]>
diff --git a/ituxd/Android.mk b/ituxd/Android.mk
new file mode 100644
index 0000000..68a7de8
--- /dev/null
+++ b/ituxd/Android.mk
@@ -0,0 +1,49 @@
+# Copyright (C) 2014 The Android Open-Source Project
+#
+# 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.
+#
+
+# WARNING: Everything listed here will be built on ALL platforms,
+# including x86, the emulator, and the SDK. Modules must be uniquely
+# named (liblights.tuna), and must build everywhere, or limit themselves
+# to only building on ARM if they include assembly. Individual makefiles
+# are responsible for having their own logic, for fine-grained control.
+
+ifeq ($(ENABLE_ITUXD),true)
+
+LOCAL_PATH:= $(call my-dir)
+
+# Build
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_JNI_SHARED_LIBRARIES := libthermalJNI
+
+LOCAL_REQUIRED_MODULES += libthermalJNI
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := ituxd
+
+LOCAL_CERTIFICATE := platform
+
+LOCAL_PRIVILEGED_MODULE := true
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
+endif
diff --git a/ituxd/AndroidManifest.xml b/ituxd/AndroidManifest.xml
new file mode 100644
index 0000000..c725d1e
--- /dev/null
+++ b/ituxd/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.intel.thermal"
+ android:sharedUserId="android.uid.system"
+>
+
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.MANAGE_USB" />
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+ <uses-permission android:name="android.permission.SHUTDOWN" />
+ <uses-permission android:name="android.permission.REBOOT" />
+
+ <protected-broadcast android:name="com.intel.thermal.action.THERMAL_ZONE_STATE_CHANGED" />
+
+ <application android:name=".ituxdApp" android:persistent="true">
+
+ <service android:enabled="true" android:name=".ThermalService"/>
+ </application>
+</manifest>
diff --git a/ituxd/jni/Android.mk b/ituxd/jni/Android.mk
new file mode 100644
index 0000000..65130f7
--- /dev/null
+++ b/ituxd/jni/Android.mk
@@ -0,0 +1,45 @@
+# Copyright (C) 2014 The Android Open-Source Project
+#
+# 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.
+#
+
+# WARNING: Everything listed here will be built on ALL platforms,
+# including x86, the emulator, and the SDK. Modules must be uniquely
+# named (liblights.tuna), and must build everywhere, or limit themselves
+# to only building on ARM if they include assembly. Individual makefiles
+# are responsible for having their own logic, for fine-grained control.
+
+ifeq ($(ENABLE_ITUXD),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= thermalJNI.cpp \
+ onload.cpp
+
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libcutils \
+ liblog \
+ libhardware \
+ libhardware_legacy \
+ libnativehelper \
+ libc \
+ libutils
+
+LOCAL_MODULE:= libthermalJNI
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/ituxd/jni/onload.cpp b/ituxd/jni/onload.cpp
new file mode 100644
index 0000000..f66a169
--- /dev/null
+++ b/ituxd/jni/onload.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+namespace android {
+int register_intel_thermal_ituxd(JNIEnv* env);
+};
+
+using namespace android;
+
+extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+ JNIEnv* env = NULL;
+ jint result = -1;
+
+ if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+ ALOGE("GetEnv failed!");
+ return result;
+ }
+ ALOG_ASSERT(env, "Could not retrieve the env!");
+
+ register_intel_thermal_ituxd(env);
+
+ return JNI_VERSION_1_4;
+}
diff --git a/ituxd/jni/thermalJNI.cpp b/ituxd/jni/thermalJNI.cpp
new file mode 100644
index 0000000..4c92775
--- /dev/null
+++ b/ituxd/jni/thermalJNI.cpp
@@ -0,0 +1,276 @@
+/*
+ * 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 "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"
+
+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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ 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];
+
+ 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 JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ {"native_readSysfs", "(Ljava/lang/String;)Ljava/lang/String;", (void*)readSysfs},
+ {"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 */
diff --git a/ituxd/res/xml/thermal_sensor_config.xml b/ituxd/res/xml/thermal_sensor_config.xml
new file mode 100644
index 0000000..5f44487
--- /dev/null
+++ b/ituxd/res/xml/thermal_sensor_config.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Thermal Management Configuration File -->
+<!-- Intel Corporation 2011-2012 -->
+<thermalconfig>
+ <!-- Config xml file version should be in sync with iTUX version number-->
+ <ConfigFileVersion>3.0</ConfigFileVersion>
+ <!--Platform Parameters-->
+ <PlatformInfo>
+ <PlatformName>fugu</PlatformName>
+ <!--namely NORMAL, WARNING, ALERT, and CRITICAL.-->
+ <!--in the increasing order of thermal severity-->
+ <!--standard sensor devices register as /sys/class/thermal/thermal_zoneX. Herein
+ referred as 'Path Enumerated at Runtime by Framework in Kernel Thermal' or PERFKT-->
+ </PlatformInfo>
+
+ <Sensor>
+ <SensorName>SYSTHERM1</SensorName>
+<!--
+ <SensorPath>auto</SensorPath>
+ <InputTemp>temp</InputTemp>
+ <HighTemp>auto</HighTemp>
+ <LowTemp>auto</LowTemp>
+-->
+ </Sensor>
+
+ <Sensor>
+ <SensorName>SYSTHERM0</SensorName>
+<!--
+ <SensorPath>auto</SensorPath>
+ <InputTemp>temp</InputTemp>
+ <HighTemp>auto</HighTemp>
+ <LowTemp>auto</LowTemp>
+-->
+ </Sensor>
+
+ <Sensor>
+ <SensorName>SoC_DTS0</SensorName>
+ <SensorPath>auto</SensorPath>
+ <InputTemp>temp</InputTemp>
+ <HighTemp>auto</HighTemp>
+ <LowTemp>auto</LowTemp>
+ </Sensor>
+
+ <Sensor>
+ <SensorName>Core0</SensorName>
+ <SensorPath>/sys/devices/platform/coretemp.0/</SensorPath>
+ <InputTemp>temp2_input</InputTemp>
+ <HighTemp>temp2_threshold2</HighTemp>
+ <LowTemp>temp2_threshold1</LowTemp>
+ <UEventDevPath>DEVPATH=/devices/platform/coretemp.0</UEventDevPath>
+ </Sensor>
+
+<!--
+ <Zone>
+ <ZoneID>1</ZoneID>
+ <ZoneName>BackSkin</ZoneName>
+ <ZoneLogic>VirtualSkin</ZoneLogic>
+ <SupportsUEvent>0</SupportsUEvent>
+ <DebounceInterval>2000</DebounceInterval>
+ <PollDelay>
+ <DelayNormal>30000</DelayNormal>
+ <DelayWarning>30000</DelayWarning>
+ <DelayAlert>30000</DelayAlert>
+ </PollDelay>
+ <ZoneThreshold>
+ <ZoneThresholdNormal>47000</ZoneThresholdNormal>
+ <ZoneThresholdWarning>57000</ZoneThresholdWarning>
+ <ZoneThresholdAlert>72000</ZoneThresholdAlert>
+ </ZoneThreshold>
+ <SensorAttrib>
+ <SensorName>SYSTHERM1</SensorName>
+ <Weight>680</Weight>
+ </SensorAttrib>
+ <Offset>8400</Offset>
+ </Zone>
+
+ <Zone>
+ <ZoneID>2</ZoneID>
+ <ZoneName>FrontSkin</ZoneName>
+ <ZoneLogic>VirtualSkin</ZoneLogic>
+ <SupportsUEvent>0</SupportsUEvent>
+ <DebounceInterval>2000</DebounceInterval>
+ <PollDelay>
+ <DelayNormal>30000</DelayNormal>
+ <DelayWarning>30000</DelayWarning>
+ <DelayAlert>30000</DelayAlert>
+ </PollDelay>
+ <ZoneThreshold>
+ <ZoneThresholdNormal>40000</ZoneThresholdNormal>
+ <ZoneThresholdWarning>50000</ZoneThresholdWarning>
+ <ZoneThresholdAlert>65000</ZoneThresholdAlert>
+ </ZoneThreshold>
+ <SensorAttrib>
+ <SensorName>SYSTHERM0</SensorName>
+ <Weight>710</Weight>
+ </SensorAttrib>
+ <Offset>8100</Offset>
+ </Zone>
+-->
+
+ <Zone>
+ <ZoneID>3</ZoneID>
+ <ZoneName>SoC</ZoneName>
+ <ZoneLogic>Raw</ZoneLogic>
+ <SupportsUEvent>0</SupportsUEvent>
+ <DebounceInterval>2000</DebounceInterval>
+ <PollDelay>
+ <DelayNormal>30000</DelayNormal>
+ <DelayWarning>10000</DelayWarning>
+ <DelayAlert>5000</DelayAlert>
+ </PollDelay>
+ <ZoneThreshold>
+ <ZoneThresholdNormal>80000</ZoneThresholdNormal>
+ <ZoneThresholdWarning>84000</ZoneThresholdWarning>
+ <ZoneThresholdAlert>88000</ZoneThresholdAlert>
+ </ZoneThreshold>
+ <SensorAttrib>
+ <SensorName>SoC_DTS0</SensorName>
+ </SensorAttrib>
+ </Zone>
+
+ <Zone>
+ <ZoneID>4</ZoneID>
+ <ZoneName>CPU</ZoneName>
+ <ZoneLogic>Raw</ZoneLogic>
+ <SupportsUEvent>0</SupportsUEvent>
+ <DebounceInterval>2000</DebounceInterval>
+ <PollDelay>
+ <DelayNormal>30000</DelayNormal>
+ <DelayWarning>10000</DelayWarning>
+ <DelayAlert>5000</DelayAlert>
+ </PollDelay>
+ <ZoneThreshold>
+ <ZoneThresholdNormal>80000</ZoneThresholdNormal>
+ <ZoneThresholdWarning>84000</ZoneThresholdWarning>
+ <ZoneThresholdAlert>88000</ZoneThresholdAlert>
+ </ZoneThreshold>
+ <SensorAttrib>
+ <SensorName>Core0</SensorName>
+ </SensorAttrib>
+ </Zone>
+ </thermalconfig>
diff --git a/ituxd/res/xml/thermal_throttle_config.xml b/ituxd/res/xml/thermal_throttle_config.xml
new file mode 100644
index 0000000..1afb1ff
--- /dev/null
+++ b/ituxd/res/xml/thermal_throttle_config.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Thermal Management Configuration File -->
+<!-- Intel Corporation 2011-2012 -->
+<thermalthrottleconfig>
+ <!-- Config xml file version should be in sync with iTUX version number-->
+ <ConfigFileVersion>3.0</ConfigFileVersion>
+
+ <!--Platform Parameters-->
+ <PlatformInfo>
+ <!--PlatformName reference. In future will be compared against ro.board.platform-->
+ <PlatformName>fugu</PlatformName>
+ <!--standard cooling devices register in /sys/class/thermal/cooling_deviceX/ Herein
+ referred as 'Path Enumerated at Runtime by Framework in Kernel Thermal' or PERFKT-->
+ </PlatformInfo>
+
+ <ContributingDeviceInfo>
+ <CDeviceName>SoC</CDeviceName>
+ <CDeviceID>1</CDeviceID>
+ <CDeviceClassPath>auto</CDeviceClassPath>
+ <CDeviceThrottlePath>auto</CDeviceThrottlePath>
+ </ContributingDeviceInfo>
+<!--
+ <ZoneThrottleInfo>
+ <ZoneID>1</ZoneID>
+ <CriticalShutDown>1</CriticalShutDown>
+ <CoolingDeviceInfo>
+ <CoolingDevId>1</CoolingDevId>
+ </CoolingDeviceInfo>
+ </ZoneThrottleInfo>
+
+ <ZoneThrottleInfo>
+ <ZoneID>2</ZoneID>
+ <CriticalShutDown>1</CriticalShutDown>
+ <CoolingDeviceInfo>
+ <CoolingDevId>1</CoolingDevId>
+ </CoolingDeviceInfo>
+ </ZoneThrottleInfo>
+-->
+ <ZoneThrottleInfo>
+ <ZoneID>3</ZoneID>
+ <CriticalShutDown>0</CriticalShutDown>
+ <CoolingDeviceInfo>
+ <CoolingDevId>1</CoolingDevId>
+ </CoolingDeviceInfo>
+ </ZoneThrottleInfo>
+
+ <ZoneThrottleInfo>
+ <ZoneID>4</ZoneID>
+ <CriticalShutDown>0</CriticalShutDown>
+ <CoolingDeviceInfo>
+ <CoolingDevId>1</CoolingDevId>
+ </CoolingDeviceInfo>
+ </ZoneThrottleInfo>
+
+</thermalthrottleconfig>
diff --git a/ituxd/src/com/intel/thermal/RawThermalZone.java b/ituxd/src/com/intel/thermal/RawThermalZone.java
new file mode 100644
index 0000000..4baba9a
--- /dev/null
+++ b/ituxd/src/com/intel/thermal/RawThermalZone.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2014 Intel Corporation All Rights Reserved.
+ *
+ * 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.
+ */
+
+package com.intel.thermal;
+
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * The RawThermalZone class extends the ThermalZone class, with a default
+ * implementation of the isZoneStateChanged() method. This computes the
+ * zone state by first computing max of all sensor temperature (in polling mode)
+ * and comparing this temperature against zone thresholds. For uevent based
+ * monitoring only the temperature of first sensor is used to compute zone state.
+ *
+ * @hide
+ */
+public class RawThermalZone extends ThermalZone {
+
+ private static final String TAG = "RawThermalZone";
+ private ThermalZoneMonitor mTzm = null;
+
+ public RawThermalZone() {
+ super();
+ // for raw zone emul temp flag is always false
+ mSupportsEmulTemp = false;
+ }
+
+ // irrespective of what flag is set in XML, emul temp flag is false for raw thermal zone
+ // over ride function. so that even if flag is 1 in XML, 0 will be written
+ public void setEmulTempFlag(int flag) {
+ mSupportsEmulTemp = false;
+ if (flag != 0) {
+ Log.i(TAG, "zone:" + getZoneName()
+ + " is a raw zone, doesnt support emulated temperature");
+ }
+ }
+
+ public void startMonitoring() {
+ mTzm = new ThermalZoneMonitor(this);
+ }
+
+ public void stopMonitoring() {
+ if (mTzm != null) {
+ mTzm.stopMonitor();
+ }
+ }
+
+ // override updateZoneTemp
+ public boolean updateZoneTemp() {
+ int curTemp = ThermalManager.INVALID_TEMP, maxCurTemp = ThermalManager.INVALID_TEMP;
+ if (isUEventSupported()) {
+ ArrayList<ThermalSensor> list = getThermalSensorList();
+ if (list != null) {
+ // for uevent based monitoring only first sensor used
+ ThermalSensor s = list.get(0);
+ if (s != null) {
+ maxCurTemp = s.getCurrTemp();
+ }
+ }
+ } else {
+ //zone temp is max of all sensor temp
+ for (ThermalSensor ts : getThermalSensorList()) {
+ if (ts != null && ts.getSensorActiveStatus()) {
+ curTemp = ts.getCurrTemp();
+ if (curTemp > maxCurTemp) {
+ maxCurTemp = curTemp;
+ }
+ }
+ }
+ }
+
+ if (maxCurTemp != ThermalManager.INVALID_TEMP) {
+ setZoneTemp(maxCurTemp);
+ // it is assumed only one sensor will be provided for moving average
+ if (getMovingAverageFlag() && !isUEventSupported()) {
+ // only for polling mode apply moving average on predicted zone temp
+ setZoneTemp(movingAverageTemp());
+ }
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/ituxd/src/com/intel/thermal/ThermalCooling.java b/ituxd/src/com/intel/thermal/ThermalCooling.java
new file mode 100644
index 0000000..66c9470
--- /dev/null
+++ b/ituxd/src/com/intel/thermal/ThermalCooling.java
@@ -0,0 +1,785 @@
+/*
+ * Copyright 2014 Intel Corporation All Rights Reserved.
+ *
+ * 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.
+ */
+
+package com.intel.thermal;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Hashtable;
+
+/**
+ * The ThermalCooling class parses the thermal_throttle_config.xml. This class
+ * receives Thermal Intents and takes appropriate actions based on the policies
+ * configured in the xml file.
+ *
+ * @hide
+ */
+public class ThermalCooling {
+ private static final String TAG = "ThermalCooling";
+ private static final String THERMAL_SHUTDOWN_NOTIFY_PATH =
+ "/sys/module/intel_mid_osip/parameters/force_shutdown_occured";
+
+ private Context mContext;
+
+ // count to keep track of zones in critical state, waiting for shutdown
+ private int mCriticalZonesCount = 0;
+ private static final Object sCriticalZonesCountLock = new Object();
+
+ private ThermalZoneReceiver mThermalIntentReceiver = new ThermalZoneReceiver();
+ private ProfileChangeReceiver mProfChangeReceiver = new ProfileChangeReceiver();
+ private boolean mProfChangeListenerInitialized = false;
+ /**
+ * This is the parser class which parses the thermal_throttle_config.xml
+ * file.
+ */
+ protected enum MetaTag {
+ ENUM_THROTTLEVALUES,
+ ENUM_THROTTLEMASK,
+ ENUM_DETHROTTLEMASK,
+ ENUM_UNKNOWN
+ }
+
+ public class ThermalParser {
+ private static final String THERMAL_THROTTLE_CONFIG = "thermalthrottleconfig";
+
+ private static final String CDEVINFO = "ContributingDeviceInfo";
+
+ private static final String ZONETHROTINFO = "ZoneThrottleInfo";
+
+ private static final String COOLINGDEVICEINFO = "CoolingDeviceInfo";
+
+ private static final String THROTTLEMASK = "ThrottleDeviceMask";
+
+ private static final String DETHROTTLEMASK = "DethrottleDeviceMask";
+
+ private static final String THROTTLEVALUES = "ThrottleValues";
+
+ private static final String COOLINGDEVICESTATES = "CoolingDeviceStates";
+
+ private static final String PROFILE = "Profile";
+
+ private ArrayList<Integer> mTempMaskList;
+
+ private ArrayList<Integer> mTempThrottleValuesList;;
+
+ private boolean done = false;
+
+ XmlPullParserFactory mFactory;
+
+ XmlPullParser mParser;
+
+ ThermalCoolingDevice mDevice = null;
+
+ /* Hashtable of (ZoneID and ZoneCoolerBindingInfo object) */
+ Hashtable<Integer, ThermalManager.ZoneCoolerBindingInfo> mZoneCoolerBindMap = null;
+ String mCurProfileName = ThermalManager.DEFAULT_PROFILE_NAME;
+ int mNumProfiles = 0;
+
+ ThermalManager.ZoneCoolerBindingInfo mZone = null;
+
+ FileReader mInputStream = null;
+
+ ThermalParser(String fname) {
+ try {
+ mFactory = XmlPullParserFactory.newInstance(
+ System.getProperty(XmlPullParserFactory.PROPERTY_NAME), null);
+ mFactory.setNamespaceAware(true);
+ mParser = mFactory.newPullParser();
+ } catch (XmlPullParserException xppe) {
+ Log.e(TAG, "mParser NewInstance Exception");
+ }
+
+ try {
+ mInputStream = new FileReader(fname);
+ if (mInputStream == null)
+ return;
+ if (mParser != null) {
+ mParser.setInput(mInputStream);
+ }
+ mDevice = null;
+ mZone = null;
+ } catch (XmlPullParserException xppe) {
+ Log.e(TAG, "mParser setInput XmlPullParserException");
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "mParser setInput FileNotFoundException");
+ }
+
+ }
+
+ ThermalParser() {
+ mParser = mContext.getResources().
+ getXml(ThermalManager.sThrottleFileXmlId);
+ }
+
+ public boolean parse() {
+ if (ThermalManager.sIsOverlays == false && mInputStream == null) return false;
+ /* if mParser is null, close any open stream before exiting */
+ if (mParser == null) {
+ try {
+ if (mInputStream != null) {
+ mInputStream.close();
+ }
+ } catch (IOException e) {
+ Log.i(TAG, "IOException caught in parse() function");
+ }
+ return false;
+ }
+
+ boolean ret = true;
+ MetaTag tag = MetaTag.ENUM_UNKNOWN;
+ try {
+ int mEventType = mParser.getEventType();
+ while (mEventType != XmlPullParser.END_DOCUMENT && !done) {
+ switch (mEventType) {
+ case XmlPullParser.START_DOCUMENT:
+ Log.i(TAG, "StartDocument");
+ break;
+ case XmlPullParser.START_TAG:
+ String tagName = mParser.getName();
+ boolean isMetaTag = false;
+ if (tagName != null && tagName.equalsIgnoreCase(THROTTLEVALUES)) {
+ tag = MetaTag.ENUM_THROTTLEVALUES;
+ isMetaTag = true;
+ } else if (tagName != null && tagName.equalsIgnoreCase(THROTTLEMASK)) {
+ tag = MetaTag.ENUM_THROTTLEMASK;
+ isMetaTag = true;
+ } else if (tagName != null
+ && tagName.equalsIgnoreCase(DETHROTTLEMASK)) {
+ tag = MetaTag.ENUM_DETHROTTLEMASK;
+ isMetaTag = true;
+ }
+ if (isMetaTag) {
+ ret = processMetaTag(tagName, tag);
+ } else {
+ ret = processStartElement(tagName);
+ }
+ if (!ret) {
+ if (mInputStream != null) mInputStream.close();
+ return false;
+ }
+ break;
+ case XmlPullParser.END_TAG:
+ processEndElement(mParser.getName());
+ break;
+ }
+ mEventType = mParser.next();
+ }
+ } catch (XmlPullParserException xppe) {
+ Log.i(TAG, "XmlPullParserException caught in parse():" + xppe.getMessage());
+ ret = false;
+ } catch (IOException e) {
+ Log.i(TAG, "IOException caught in parse():" + e.getMessage());
+ ret = false;
+ } finally {
+ try {
+ // end of parsing, close the stream
+ // close is moved here, since if there is an exception
+ // while parsing doc, input stream needs to be closed
+ if (mInputStream != null) {
+ mInputStream.close();
+ }
+ } catch (IOException e) {
+ Log.i(TAG, "IOException caught in parse() function");
+ ret = false;
+ }
+ return ret;
+ }
+ }
+
+ public boolean processMetaTag(String tagName, MetaTag tagId) {
+ if (mParser == null || tagName == null) return false;
+ ArrayList<Integer> tempList = new ArrayList<Integer>();
+ try {
+ int eventType = mParser.next();
+ while (true) {
+ if (eventType == XmlPullParser.START_TAG) {
+ tempList.add(Integer.parseInt(mParser.nextText()));
+ } else if (eventType == XmlPullParser.END_TAG &&
+ mParser.getName().equalsIgnoreCase(tagName)) {
+ break;
+ }
+ eventType = mParser.next();
+ }
+ } catch (XmlPullParserException xppe) {
+ Log.e(TAG, "XmlPullParserException:" + xppe.getMessage());
+ return false;
+ } catch (IOException ioe) {
+ Log.e(TAG, "IOException:" + ioe.getMessage());
+ return false;
+ }
+
+ switch(tagId) {
+ case ENUM_THROTTLEVALUES:
+ if (mDevice == null) {
+ return false;
+ } else {
+ // add throttle value for TCRITICAL (same as last value)
+ tempList.add(tempList.get(tempList.size() - 1));
+ mDevice.setThrottleValuesList(tempList);
+ }
+ break;
+ case ENUM_THROTTLEMASK:
+ if (mZone == null || mZone.getLastCoolingDeviceInstance() == null) {
+ return false;
+ } else {
+ // Always throttle at CRITICAL state (last state)
+ tempList.add(1);
+ mZone.getLastCoolingDeviceInstance().setThrottleMaskList(tempList);
+ }
+ break;
+ case ENUM_DETHROTTLEMASK:
+ if (mZone == null || mZone.getLastCoolingDeviceInstance() == null) {
+ return false;
+ } else {
+ // Dethrottling at CRITICAL state (last state) is dontcare condition
+ tempList.add(0);
+ mZone.getLastCoolingDeviceInstance().setDeThrottleMaskList(tempList);
+ }
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+ boolean processStartElement(String name) {
+ if (name == null)
+ return false;
+ boolean ret = true;
+ try {
+ if (name.equalsIgnoreCase(CDEVINFO)) {
+ if (mDevice == null)
+ mDevice = new ThermalCoolingDevice();
+ } else if (name.equalsIgnoreCase(ZONETHROTINFO)) {
+ if (mZone == null) {
+ mZone = new ThermalManager.ZoneCoolerBindingInfo();
+ }
+ if (mZoneCoolerBindMap == null) {
+ mZoneCoolerBindMap = new Hashtable<Integer,
+ ThermalManager.ZoneCoolerBindingInfo>();
+ }
+ } else if (name.equalsIgnoreCase(PROFILE)) {
+ mNumProfiles++;
+ if (mZoneCoolerBindMap == null) {
+ mZoneCoolerBindMap = new Hashtable<Integer,
+ ThermalManager.ZoneCoolerBindingInfo>();
+ }
+ } else if (name.equalsIgnoreCase(COOLINGDEVICEINFO) && mZone != null) {
+ if (mZone.getCoolingDeviceInfoList() == null) {
+ mZone.initializeCoolingDeviceInfoList();
+ }
+ mZone.createNewCoolingDeviceInstance();
+ } else {
+ // Retrieve zone and cooling device mapping
+ if (name.equalsIgnoreCase("ZoneID") && mZone != null) {
+ mZone.setZoneID(Integer.parseInt(mParser.nextText()));
+ } else if (name.equalsIgnoreCase("CriticalShutDown") && mZone != null) {
+ mZone.setCriticalActionShutdown(Integer.parseInt(mParser.nextText()));
+ } else if (name.equalsIgnoreCase(THROTTLEMASK) && mZone != null) {
+ mTempMaskList = new ArrayList<Integer>();
+ } else if (name.equalsIgnoreCase(DETHROTTLEMASK) && mZone != null) {
+ mTempMaskList = new ArrayList<Integer>();
+ } else if (name.equalsIgnoreCase("CoolingDevId") && mZone != null) {
+ mZone.getLastCoolingDeviceInstance().setCoolingDeviceId(
+ Integer.parseInt(mParser.nextText()));
+ } else if (name.equalsIgnoreCase(COOLINGDEVICESTATES) && mZone != null) {
+ // Increase cooling device states by 1, required for CRITICAL state
+ mZone.getLastCoolingDeviceInstance().setCoolingDeviceStates(
+ Integer.parseInt(mParser.nextText()) + 1);
+ }
+ // Retrieve cooling device information
+ if (name.equalsIgnoreCase("CDeviceName") && mDevice != null) {
+ mDevice.setDeviceName(mParser.nextText());
+ } else if (name.equalsIgnoreCase("CDeviceID") && mDevice != null) {
+ mDevice.setDeviceId(Integer.parseInt(mParser.nextText()));
+ } else if (name.equalsIgnoreCase("CDeviceClassPath") && mDevice != null) {
+ mDevice.setClassPath(mParser.nextText());
+ } else if (name.equalsIgnoreCase("CDeviceThrottlePath") && mDevice != null) {
+ mDevice.setThrottlePath(mParser.nextText());
+ } else if (name.equalsIgnoreCase("Name")) {
+ mCurProfileName = mParser.nextText();
+ }
+ }
+ } catch (XmlPullParserException e) {
+ Log.i(TAG, "XmlPullParserException caught in processStartElement()");
+ ret = false;
+ } catch (IOException e) {
+ Log.i(TAG, "IOException caught in processStartElement()");
+ ret = false;
+ } finally {
+ return ret;
+ }
+ }
+
+ void processEndElement(String name) {
+ if (name == null)
+ return;
+ if (name.equalsIgnoreCase(CDEVINFO) && mDevice != null) {
+ // if cooling dev suports less then DEFAULT throttle values donot add to map.
+ if (mDevice.getNumThrottleValues() < ThermalManager.DEFAULT_NUM_THROTTLE_VALUES) {
+ Log.i(TAG, "cooling dev:" + mDevice.getDeviceName()
+ + " deactivated! throttle values < "
+ + ThermalManager.DEFAULT_NUM_THROTTLE_VALUES);
+ mDevice = null;
+ return;
+ }
+ if (mDevice.getThrottlePath().equals("auto")) {
+ mDevice.setThrottlePath("auto");
+ }
+ if (loadCoolingDevice(mDevice)) {
+ ThermalManager.sCDevMap.put(mDevice.getDeviceId(), mDevice);
+ }
+ mDevice = null;
+ } else if (name.equalsIgnoreCase(ZONETHROTINFO) && mZone != null) {
+ mZone.printAttributes();
+ if (mZoneCoolerBindMap != null) {
+ mZoneCoolerBindMap.put(mZone.getZoneID(), mZone);
+ }
+ mZone = null;
+ } else if (name.equalsIgnoreCase(PROFILE)) {
+ if (mZoneCoolerBindMap != null) {
+ ThermalManager.sProfileBindMap.put(mCurProfileName, mZoneCoolerBindMap);
+ mZoneCoolerBindMap = new Hashtable<Integer,
+ ThermalManager.ZoneCoolerBindingInfo>();
+ }
+ } else if (name.equalsIgnoreCase(THERMAL_THROTTLE_CONFIG)) {
+ Log.i(TAG, "Parsing Finished..");
+ // This indicates we have not seen any <Profile> tag.
+ // Consider it as if we have only one 'Default' Profile.
+ if (mNumProfiles == 0 && mZoneCoolerBindMap != null) {
+ ThermalManager.sProfileBindMap.put(mCurProfileName, mZoneCoolerBindMap);
+ }
+ done = true;
+ } else if (name.equalsIgnoreCase(COOLINGDEVICEINFO) && mZone != null) {
+ ThermalManager.ZoneCoolerBindingInfo.CoolingDeviceInfo cDevInfo;
+ cDevInfo = mZone.getLastCoolingDeviceInstance();
+ if (cDevInfo != null) {
+ ThermalCoolingDevice cDev = ThermalManager.sCDevMap
+ .get(cDevInfo.getCoolingDeviceId());
+ if (cDev == null) return;
+ int cds = cDevInfo.getCoolingDeviceStates();
+ // check the CDS against the number of throttle values exposed.
+ // If exceeds, cap it.
+ if (cds > cDev.getNumThrottleValues()) {
+ cDevInfo.setCoolingDeviceStates(cDev.getNumThrottleValues());
+ Log.i(TAG, "capping cdevid: " + cDevInfo.getCoolingDeviceId()
+ + " to " + cDev.getNumThrottleValues() + " states");
+ }
+ if (cDevInfo.checkMaskList(cDev.getNumThrottleValues())) {
+ // add only active cooling devices to list
+ mZone.addCoolingDeviceToList(cDevInfo);
+ }
+ }
+ }
+ }
+ }
+
+ private void configureDynamicTurbo() {
+ // Disable Dynamic Turbo based on the system property
+ int indx = ThermalUtils.getCoolingDeviceIndexContains("SoC");
+ if (indx != -1 && !ThermalManager.sIsDynamicTurboEnabled) {
+ String path = ThermalManager.sCoolingDeviceBasePath + indx
+ + ThermalManager.sCoolingDeviceState;
+ ThermalUtils.writeSysfs(path, ThermalManager.DISABLE_DYNAMIC_TURBO);
+ }
+ }
+
+ public boolean init(Context context) {
+ Log.i(TAG, "Thermal Cooling manager init() called");
+
+ mContext = context;
+ ThermalParser parser;
+ if (!ThermalManager.sIsOverlays) {
+ parser = new ThermalParser(ThermalManager.sThrottleFilePath);
+ } else {
+ parser = new ThermalParser();
+ }
+
+ if (parser == null || !parser.parse()) {
+ Log.i(TAG, "thermal_throttle_config.xml parsing failed");
+ return false;
+ }
+
+ // Set this sZoneCoolerBindMap to the DefaultProfile Map
+ ThermalManager.setCurBindMap(ThermalManager.DEFAULT_PROFILE_NAME);
+
+ // Register for thermal zone state changed notifications
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ThermalManager.ACTION_THERMAL_ZONE_STATE_CHANGED);
+ mContext.registerReceiver(mThermalIntentReceiver, filter);
+
+ configureDynamicTurbo();
+ return true;
+ }
+
+ private final class ProfileChangeReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(ThermalManager.ACTION_CHANGE_THERMAL_PROFILE)) {
+ String profName = intent.getStringExtra(ThermalManager.EXTRA_PROFILE);
+ if (profName != null) {
+ ThermalManager.changeThermalProfile(profName);
+ }
+ }
+ }
+ }
+
+ private void incrementCrticalZoneCount() {
+ synchronized(sCriticalZonesCountLock) {
+ mCriticalZonesCount++;
+ }
+ }
+
+ private final class ThermalZoneReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String zoneName = intent.getStringExtra(ThermalManager.EXTRA_NAME);
+ String profName = intent.getStringExtra(ThermalManager.EXTRA_PROFILE);
+ int thermZone = intent.getIntExtra(ThermalManager.EXTRA_ZONE, -1);
+ int thermState = intent.getIntExtra(ThermalManager.EXTRA_STATE, 0);
+ int thermEvent = intent.getIntExtra(ThermalManager.EXTRA_EVENT, 0);
+ int zoneTemp = intent.getIntExtra(ThermalManager.EXTRA_TEMP, 0);
+
+ // Assume 'Default' profile if there is no profile parameter
+ // as part of the intent.
+ if (profName == null) {
+ profName = ThermalManager.DEFAULT_PROFILE_NAME;
+ }
+
+ Log.i(TAG, "Received THERMAL INTENT:(ProfileName, ZoneName, State, EventType, Temp):"
+ + "(" + profName + ", " + zoneName + ", " + thermState + ", "
+ + ThermalZone.getEventTypeAsString(thermEvent) + ", " + zoneTemp + ")");
+
+ Hashtable<Integer, ThermalManager.ZoneCoolerBindingInfo> mBindMap =
+ ThermalManager.getBindMap(profName);
+ if (mBindMap == null) {
+ Log.i(TAG, "mBindMap null inside ThermalZoneReceiver");
+ return;
+ }
+
+ ThermalManager.ZoneCoolerBindingInfo zoneCoolerBindInfo = mBindMap.get(thermZone);
+ if (zoneCoolerBindInfo == null) {
+ Log.i(TAG, "zoneCoolerBindInfo null for zoneID" + thermZone);
+ return;
+ }
+
+ boolean flag = zoneCoolerBindInfo.getCriticalActionShutdown() == 1;
+ int lastState = zoneCoolerBindInfo.getLastState();
+ if (thermState < lastState) {
+ ThermalManager.updateZoneCriticalPendingMap(thermZone,
+ ThermalManager.CRITICAL_FALSE);
+ } else if (thermState == lastState && flag) {
+ /* no telephony support, so (!isEmergencyCallOnGoing) is true */
+ if (true) {
+ doShutdown();
+ } else {
+ // increment the count of zones in critical state pending on shutdown
+ ThermalManager.updateZoneCriticalPendingMap(thermZone,
+ ThermalManager.CRITICAL_TRUE);
+ }
+ }
+
+ /* if THERMALOFF is the zone state, it is guaranteed that the zone has transitioned
+ from a higher state, due to a low event, to THERMALOFF.Hence take de-throttling action
+ corresponding to NORMAL */
+ if (thermState == ThermalManager.THERMAL_STATE_OFF) {
+ thermState = ThermalManager.THERMAL_STATE_NORMAL;
+ }
+ handleThermalEvent(thermZone, thermEvent, thermState, zoneCoolerBindInfo);
+ }
+ }
+
+ private boolean loadCoolingDevice(ThermalCoolingDevice device) {
+ Class cls;
+ Method throttleMethod;
+ String classPath = device.getClassPath();
+
+ if (classPath == null) {
+ Log.i(TAG, "ClassPath not found");
+ return false;
+ }
+
+ if (classPath.equalsIgnoreCase("none") || classPath.equalsIgnoreCase("auto")
+ || classPath.equalsIgnoreCase("AppAgent")) {
+ Log.i(TAG, "ClassPath: none/auto/AppAgent");
+ return true;
+ }
+
+ /* Load the cooling device class */
+ try {
+ cls = Class.forName(classPath);
+ device.setDeviceClass(cls);
+ } catch (Throwable e) {
+ Log.i(TAG, "Unable to load class " + classPath);
+ return false;
+ }
+
+ /* Initialize the cooling device class */
+ try {
+ Class partypes[] = new Class[3];
+ partypes[0] = Context.class;
+ partypes[1] = String.class;
+ partypes[2] = ArrayList.class;
+ Method init = cls.getMethod("init", partypes);
+ Object arglist[] = new Object[3];
+ arglist[0] = mContext;
+ arglist[1] = device.getThrottlePath();
+ arglist[2] = device.getThrottleValuesList();
+ init.invoke(cls, arglist);
+ } catch (NoSuchMethodException e) {
+ Log.i(TAG, "NoSuchMethodException caught in device class init: " + classPath);
+ } catch (SecurityException e) {
+ Log.i(TAG, "SecurityException caught in device class init: " + classPath);
+ } catch (IllegalAccessException e) {
+ Log.i(TAG, "IllegalAccessException caught in device class init: " + classPath);
+ } catch (IllegalArgumentException e) {
+ Log.i(TAG, "IllegalArgumentException caught in device class init: " + classPath);
+ } catch (ExceptionInInitializerError e) {
+ Log.i(TAG, "ExceptionInInitializerError caught in device class init: " + classPath);
+ } catch (InvocationTargetException e) {
+ Log.i(TAG, "InvocationTargetException caught in device class init: " + classPath);
+ }
+
+ /* Get the throttleDevice method from cooling device class */
+ try {
+ Class partypes[] = new Class[1];
+ partypes[0] = Integer.TYPE;
+ throttleMethod = cls.getMethod("throttleDevice", partypes);
+ device.setThrottleMethod(throttleMethod);
+ } catch (NoSuchMethodException e) {
+ Log.i(TAG, "NoSuchMethodException caught initializing throttle function");
+ } catch (SecurityException e) {
+ Log.i(TAG, "SecurityException caught initializing throttle function");
+ }
+
+ return true;
+ }
+
+
+ public void doShutdown() {
+ ThermalUtils.writeSysfs(THERMAL_SHUTDOWN_NOTIFY_PATH, 1);
+ /* We must avoid reboot after shutdown. */
+ SystemProperties.set("sys.property_forcedshutdown", "1");
+ Intent criticalIntent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
+ criticalIntent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
+ criticalIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ Log.i(TAG, "Thermal Service initiating shutdown");
+ mContext.startActivity(criticalIntent);
+ }
+
+ public void registerProfChangeListener() {
+ IntentFilter profChangeIntentFilter = new IntentFilter();
+ profChangeIntentFilter.addAction(ThermalManager.ACTION_CHANGE_THERMAL_PROFILE);
+ // TODO: add some permission (BRICK ??) to protect it from third party apps
+ mContext.registerReceiver(mProfChangeReceiver, profChangeIntentFilter);
+ mProfChangeListenerInitialized = true;
+ }
+
+ /* Method to handle the thermal event based on HIGH or LOW event */
+ private void handleThermalEvent(int zoneId, int eventType, int thermalState,
+ ThermalManager.ZoneCoolerBindingInfo zoneCoolerBindInfo) {
+ ThermalCoolingDevice tDevice;
+ int deviceId;
+ int existingState, targetState;
+ int currThrottleMask, currDethrottleMask;
+ int index = 0;
+
+ if (zoneCoolerBindInfo.getCoolingDeviceInfoList() == null)
+ return;
+
+ for (ThermalManager.ZoneCoolerBindingInfo.CoolingDeviceInfo CdeviceInfo :
+ zoneCoolerBindInfo.getCoolingDeviceInfoList()) {
+ int coolingDeviceState = thermalState /
+ zoneCoolerBindInfo.getZoneToCoolDevBucketSizeIndex(index);
+ // cap it
+ coolingDeviceState = (coolingDeviceState > (CdeviceInfo.getCoolingDeviceStates() - 1))
+ ? CdeviceInfo.getCoolingDeviceStates() - 1 : coolingDeviceState;
+ int finalThrottleState = coolingDeviceState *
+ zoneCoolerBindInfo.getCoolDevToThrottBucketSizeIndex(index);
+ // cap it
+ finalThrottleState = (finalThrottleState > (CdeviceInfo.getMaxThrottleStates() - 1))
+ ? CdeviceInfo.getMaxThrottleStates() - 1 : finalThrottleState;
+ index++;
+ if (ThermalManager.THERMAL_HIGH_EVENT == eventType) {
+ ArrayList<Integer> throttleMaskList = CdeviceInfo.getThrottleMaskList();
+ if (throttleMaskList == null) continue;
+ // cap to avoid out of bound exception
+ coolingDeviceState = (coolingDeviceState > throttleMaskList.size() - 1)
+ ? throttleMaskList.size() - 1 : coolingDeviceState;
+ currThrottleMask = throttleMaskList.get(coolingDeviceState);
+ deviceId = CdeviceInfo.getCoolingDeviceId();
+
+ tDevice = ThermalManager.sCDevMap.get(deviceId);
+ if (tDevice == null)
+ continue;
+
+ if (currThrottleMask == ThermalManager.THROTTLE_MASK_ENABLE) {
+ existingState = tDevice.getThermalState();
+ tDevice.updateZoneState(zoneId, finalThrottleState);
+ targetState = tDevice.getThermalState();
+
+ /* Do not throttle if device is already in desired state.
+ * (We can save Sysfs write)
+ * */
+ if (existingState != targetState) throttleDevice(deviceId, targetState);
+
+ } else {
+ // If throttle mask is not enabled, don't do anything here.
+ }
+ }
+
+ if (ThermalManager.THERMAL_LOW_EVENT == eventType) {
+ ArrayList<Integer> dethrottleMaskList = CdeviceInfo.getDeThrottleMaskList();
+ if (dethrottleMaskList == null) continue;
+ // cap to avoid out of bound exception
+ coolingDeviceState = (coolingDeviceState > dethrottleMaskList.size() - 1)
+ ? dethrottleMaskList.size() - 1 : coolingDeviceState;
+ currDethrottleMask = dethrottleMaskList.get(coolingDeviceState);
+ deviceId = CdeviceInfo.getCoolingDeviceId();
+
+ tDevice = ThermalManager.sCDevMap.get(deviceId);
+ if (tDevice == null)
+ continue;
+
+ existingState = tDevice.getThermalState();
+ tDevice.updateZoneState(zoneId, finalThrottleState);
+ targetState = tDevice.getThermalState();
+
+ /* Do not dethrottle if device is already in desired state.
+ * (We can save Sysfs write) */
+ if ((existingState != targetState) &&
+ (currDethrottleMask == ThermalManager.DETHROTTLE_MASK_ENABLE)) {
+ throttleDevice(deviceId, targetState);
+ }
+ }
+ }
+
+ }
+
+ /*
+ * defaultThrottleMethod is called for cooling devices for which an additional
+ * plugin file is not provided. Since the throttle path and the throttle values
+ * are known, we dont need an additional plugin to implement the policy. This info
+ * is provided via thermal_throttle_config file. If for a cooling device,
+ * Assumptions -
+ * 1. If CDeviceClassPath is 'auto' this triggers a call to defaultThrottleMethod().
+ * if a false throttle path is provided, the write fails and function exits gracefully
+ * with a warning message.
+ * 2. If 'auto' mode is used for CDeviceClassPath, and no throttle values are provided,
+ * thermal state will be written.
+ * 3. If CDeviceThrottlePath is 'auto', then throttle path will be constrcuted.
+ * The Cooling device name should contain a subset string that matches the type for
+ * /sys/class/thermal/cooling_deviceX/type inorder to find the right index X
+ * 4. CDeviceThrottlePath is null no write operation will be done
+ **/
+ private void defaultThrottleMethod(ThermalCoolingDevice cdev, int level) {
+ int finalValue;
+ String throttlePath = null;
+
+ if (cdev == null) return;
+
+ if (level < cdev.getNumThrottleValues() - 1) {
+ try {
+ ArrayList<Integer> values = cdev.getThrottleValuesList();
+ if (values == null || values.size() == 0) {
+ finalValue = level;
+ } else {
+ finalValue = values.get(level);
+ }
+
+ throttlePath = cdev.getThrottlePath();
+ if (throttlePath == null) {
+ Log.w(TAG, "throttle path is null");
+ return;
+ }
+
+ if (!ThermalUtils.isFileExists(throttlePath)) {
+ Log.w(TAG, "invalid throttle path for cooling device:" + cdev.getDeviceName());
+ return;
+ }
+
+ if (ThermalUtils.writeSysfs(throttlePath, finalValue) == -1) {
+ Log.w(TAG, "write to sysfs failed");
+ }
+ } catch (IndexOutOfBoundsException e) {
+ Log.w(TAG, "IndexOutOfBoundsException caught in defaultThrottleMethod()");
+ }
+ }
+ }
+
+ /* Method to throttle cooling device */
+ private void throttleDevice(int coolingDevId, int throttleLevel) {
+ /* Retrieve the cooling device based on ID */
+ ThermalCoolingDevice dev = ThermalManager.sCDevMap.get(coolingDevId);
+ if (dev != null) {
+ if (dev.getClassPath() != null && dev.getClassPath().equalsIgnoreCase("auto")) {
+ defaultThrottleMethod(dev, throttleLevel);
+ } else {
+ Class c = dev.getDeviceClass();
+ Method throt = dev.getThrottleMethod();
+ if (throt == null)
+ return;
+ Object arglist[] = new Object[1];
+ arglist[0] = new Integer(throttleLevel);
+
+ // Invoke the throttle method passing the throttle level as parameter
+ try {
+ throt.invoke(c, arglist);
+ } catch (IllegalAccessException e) {
+ Log.i(TAG, "IllegalAccessException caught throttleDevice() ");
+ } catch (IllegalArgumentException e) {
+ Log.i(TAG, "IllegalArgumentException caught throttleDevice() ");
+ } catch (ExceptionInInitializerError e) {
+ Log.i(TAG, "ExceptionInInitializerError caught throttleDevice() ");
+ } catch (SecurityException e) {
+ Log.i(TAG, "SecurityException caught throttleDevice() ");
+ } catch (InvocationTargetException e) {
+ Log.i(TAG, "InvocationTargetException caught throttleDevice() ");
+ }
+ }
+ } else {
+ Log.i(TAG, "throttleDevice: Unable to retrieve cooling device " + coolingDevId);
+ }
+ }
+
+ public void unregisterReceivers() {
+ if (mContext != null) {
+ mContext.unregisterReceiver(mThermalIntentReceiver);
+ // During Thermal Service init, when parsing fails, we
+ // unregister all receivers here. mProfChangeReceiver
+ // might not have been initialized at that time because
+ // we initialize this only after starting the Default profile.
+ if (mProfChangeListenerInitialized) {
+ mContext.unregisterReceiver(mProfChangeReceiver);
+ }
+ }
+ }
+}
diff --git a/ituxd/src/com/intel/thermal/ThermalCoolingDevice.java b/ituxd/src/com/intel/thermal/ThermalCoolingDevice.java
new file mode 100644
index 0000000..4a97eb0
--- /dev/null
+++ b/ituxd/src/com/intel/thermal/ThermalCoolingDevice.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2014 Intel Corporation All Rights Reserved.
+ *
+ * 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.
+ */
+
+package com.intel.thermal;
+
+import android.util.Log;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+
+/**
+ * This class contains the cooling device specific information. It also contains
+ * a reference to the actual throttle function.
+ *
+ * @hide
+ */
+public class ThermalCoolingDevice {
+
+ private static final String TAG = "ThermalCoolingDevice";
+
+ private String mDeviceName;
+
+ private String mClassPath;
+
+ private String mThrottlePath;
+
+ private int mCurrentThermalState;
+
+ private int mDeviceId;
+
+ private Class mDeviceClass;
+
+ private Method mThrottleMethod;
+
+ /* Maintains list of zoneid's under which this cooling device falls. */
+ private ArrayList<Integer> mZoneIdList = new ArrayList<Integer>();
+
+ /* Maintains corresponding state of zone present in mZoneidList */
+ private ArrayList<Integer> mZoneStateList = new ArrayList<Integer>();
+
+ /* List of values used to throttle this cooling device */
+ private ArrayList<Integer> mThrottleValues = null;
+
+ private int mNumThrottleValues = ThermalManager.DEFAULT_NUM_THROTTLE_VALUES;
+
+ public ThermalCoolingDevice() {
+ mCurrentThermalState = -1;
+ mThrottlePath = "auto";
+ mClassPath = "auto";
+ }
+
+ public void setNumThrottleValues(int num) {
+ mNumThrottleValues = num;
+ }
+
+ public int getNumThrottleValues() {
+ return mNumThrottleValues;
+ }
+
+ public void setDeviceName(String Name) {
+ mDeviceName = Name;
+ }
+
+ public String getDeviceName() {
+ return mDeviceName;
+ }
+
+ public void setDeviceId(int deviceId) {
+ mDeviceId = deviceId;
+ }
+
+ public int getDeviceId() {
+ return mDeviceId;
+ }
+
+ public String getClassPath() {
+ return mClassPath;
+ }
+
+ public void setClassPath(String Path) {
+ mClassPath = Path;
+ }
+
+ public Class getDeviceClass() {
+ return mDeviceClass;
+ }
+
+ public void setDeviceClass(Class cls) {
+ mDeviceClass = cls;
+ }
+
+ public Method getThrottleMethod() {
+ return mThrottleMethod;
+ }
+
+ public void setThrottleMethod(Method method) {
+ mThrottleMethod = method;
+ }
+
+ public String getThrottlePath() {
+ return mThrottlePath;
+ }
+
+ public void setThrottlePath(String path) {
+ if (path.equalsIgnoreCase("auto") && !mDeviceName.equalsIgnoreCase("battery")) {
+ //construct the throttle path
+ int indx = ThermalUtils.getCoolingDeviceIndexContains(mDeviceName);
+ if (indx != -1) {
+ mThrottlePath = ThermalManager.sCoolingDeviceBasePath + indx +
+ ThermalManager.sCoolingDeviceState;
+ } else {
+ mThrottlePath = "invalid";
+ }
+ } else {
+ mThrottlePath = path;
+ }
+ }
+
+ public ArrayList<Integer> getZoneIdList() {
+ return mZoneIdList;
+ }
+
+ public ArrayList<Integer> getZoneStateList() {
+ return mZoneStateList;
+ }
+
+ public ArrayList<Integer> getThrottleValuesList() {
+ return mThrottleValues;
+ }
+
+ public void setThrottleValuesList(ArrayList<Integer> list) {
+ mThrottleValues = list;
+ mNumThrottleValues = list.size();
+ }
+ /**
+ * Sets the current thermal state of cooling device which will be maximum of
+ * all states of zones under which this cooling device falls.
+ */
+ private void updateCurrentThermalState() {
+ int state = 0;
+ for (Integer coolingDevState : mZoneStateList) {
+ state = Math.max(state, coolingDevState);
+ }
+ mCurrentThermalState = state;
+ }
+
+ /**
+ * Adds zoneID and its thermal state to mListOfZoneIDs and
+ * mListOfTStatesOfZones array. If zoneId exists then its thermal state is
+ * updated else zoneId and its state will be added to array.
+ */
+ public void updateZoneState(int zoneId, int state) {
+ int index = -1;
+
+ if (!mZoneIdList.isEmpty()) {
+ index = mZoneIdList.indexOf(zoneId);
+ }
+
+ // Entry does not exist
+ if (index == -1) {
+ mZoneIdList.add(zoneId);
+ mZoneStateList.add(state);
+ } else {
+ mZoneStateList.set(index, state);
+ }
+
+ updateCurrentThermalState();
+ }
+
+ public int getThermalState() {
+ return mCurrentThermalState;
+ }
+
+}
diff --git a/ituxd/src/com/intel/thermal/ThermalEvent.java b/ituxd/src/com/intel/thermal/ThermalEvent.java
new file mode 100644
index 0000000..ebc2e79
--- /dev/null
+++ b/ituxd/src/com/intel/thermal/ThermalEvent.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2014 Intel Corporation All Rights Reserved.
+ *
+ * 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.
+ */
+
+package com.intel.thermal;
+
+/**
+ * The ThermalEvent class contains strings and constants used for values
+ * in the ACTION_THERMAL_ZONE_STATE_CHANGED Intent.
+ *
+ * @hide
+ */
+public class ThermalEvent {
+ public int mZoneId, mEventType, mThermalLevel, mZoneTemp;
+ public String mZoneName, mProfName;
+
+ ThermalEvent(int id, int type, int state, int temp, String zoneName, String profName) {
+ mZoneId = id;
+ mEventType = type;
+ mThermalLevel = state;
+ mZoneTemp = temp;
+ mZoneName = zoneName;
+ mProfName = profName;
+ }
+}
diff --git a/ituxd/src/com/intel/thermal/ThermalManager.java b/ituxd/src/com/intel/thermal/ThermalManager.java
new file mode 100644
index 0000000..b68bd3d
--- /dev/null
+++ b/ituxd/src/com/intel/thermal/ThermalManager.java
@@ -0,0 +1,788 @@
+/*
+ * Copyright 2014 Intel Corporation All Rights Reserved.
+ *
+ * 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.
+ */
+
+package com.intel.thermal;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.NumberFormatException;
+import java.lang.StringBuilder;
+import java.util.ArrayList;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+/**
+ * The ThermalManager class contains data structures that are common to both
+ * Thermal Sensor/Zone and Cooling device parts.
+ *
+ * @hide
+ */
+public class ThermalManager {
+ private static final String TAG = "ThermalManager";
+ private static Context sContext;
+ private static String sVersion;
+ private static String sCurProfileName;
+ private static String sProfileNameList;
+ private static int sProfileCount;
+ private static final String ITUX_VERSION_PROPERTY = "ro.thermal.ituxversion";
+ /* Parameter needed for reading configuration files */
+ public static final String SENSOR_FILE_NAME = "thermal_sensor_config.xml";
+ public static final String THROTTLE_FILE_NAME = "thermal_throttle_config.xml";
+ public static final String DEFAULT_DIR_PATH = "/system/etc/";
+ public static final String DEBUG_DIR_PATH = "/data/";
+ public static String sSensorFilePath;
+ public static String sThrottleFilePath;
+ /* *XmlId's are assigned if config files are choosen from overlays */
+ public static int sSensorFileXmlId = -1;
+ public static int sThrottleFileXmlId = -1;
+ /* Set to true if config are available in DEFAULT or DEBUG path */
+ public static boolean sIsConfigFiles = false;
+ /* Whether we are using the config files from overlays directory or from /etc/ */
+ public static boolean sIsOverlays = false;
+ /* Parameters required for MaxTrip data */
+ public static final String TJMAX_PATH = "/sys/devices/platform/coretemp.0/temp2_crit";
+ public static final int sDefaultTjMax = 90000;
+ public static int sTjMaxTemp;
+ public static final int sMaxSkinTrip = 150000;
+
+ public static String sUEventDevPath = "DEVPATH=/devices/virtual/thermal/thermal_zone";
+ /**
+ * Thermal Zone State Changed Action: This is broadcast when the state of a
+ * thermal zone changes.
+ */
+ public static final String ACTION_THERMAL_ZONE_STATE_CHANGED =
+ "com.intel.thermal.action.THERMAL_ZONE_STATE_CHANGED";
+
+ public static PlatformInfo sPlatformInfo;
+ public static ThermalCooling sCoolingManager;
+ /* List of Thermal zones for current profile. Access protected by 'sProfileSwitchLock' */
+ private static ArrayList<ThermalZone> sThermalZonesList;
+
+ /* Hashtable of (ProfileName and ListOfZonesUnderThisProfile) */
+ public static Hashtable<String, ArrayList<ThermalZone>> sProfileZoneMap =
+ new Hashtable<String, ArrayList<ThermalZone>>();
+
+ /**
+ * This holds the map for the current profile. Access protected by 'sProfileSwitchLock'.
+ * Should be initialized for every profile change.
+ */
+ private static Hashtable<Integer, ZoneCoolerBindingInfo> sZoneCoolerBindMap =
+ new Hashtable<Integer, ZoneCoolerBindingInfo>();
+
+ /* Hashtable of (ProfileName and Hashtable(zoneID, ZoneCoolerBindingInfo) object */
+ public static Hashtable<String, Hashtable<Integer, ZoneCoolerBindingInfo>> sProfileBindMap =
+ new Hashtable<String, Hashtable<Integer, ZoneCoolerBindingInfo>>();
+
+ /* Hashtable of (Cooling Device ID and ThermalCoolingDevice object) */
+ public static Hashtable<Integer, ThermalCoolingDevice> sCDevMap =
+ new Hashtable<Integer, ThermalCoolingDevice>();
+
+ /* Hashtable of sensor name and sensor object */
+ public static Hashtable<String, ThermalSensor> sSensorMap =
+ new Hashtable<String, ThermalSensor>();
+
+ public static final int CRITICAL_TRUE = 1;
+ public static final int CRITICAL_FALSE = 0;
+ /* sZoneCriticalPendingMap stores info whether a zone is in critical state and platform
+ * shutdown has not yet occured due to some scenario like ongoing emergency call
+ **/
+ public static Hashtable<Integer, Integer> sZoneCriticalPendingMap = null;
+ /* this lock is to access sZoneCriticalPendingMap synchronously */
+ private static final Object sCriticalPendingLock = new Object();
+ /* this count keeps track of number of zones in pending critical state.When
+ * sZoneCriticalPendingMap is updated, the count is either incremented or
+ * decremented depending on whether criical pending flag for a zone is true/
+ * false. By keeping a count we can avoid scanning through the entire map to
+ * see if there is a pending critical shutdown
+ **/
+ private static int sCriticalZonesCount = 0;
+
+ /* Blocking queue to hold thermal events from thermal zones */
+ private static final int EVENT_QUEUE_SIZE = 10;
+
+ public static BlockingQueue<ThermalEvent> sEventQueue = new ArrayBlockingQueue<ThermalEvent>(EVENT_QUEUE_SIZE);
+ /* this lock is to handle uevent callbacks synchronously */
+ private static final Object sLock = new Object();
+
+ /**
+ * Extra for {@link ACTION_THERMAL_ZONE_STATE_CHANGED}:
+ * integer containing the thermal zone.
+ */
+ public static final String EXTRA_ZONE = "zone";
+
+ /**
+ * Extra for {@link ACTION_THERMAL_ZONE_STATE_CHANGED}:
+ * integer containing the thermal state of the zone.
+ */
+ public static final String EXTRA_STATE = "state";
+
+ /**
+ * Extra for {@link ACTION_THERMAL_ZONE_STATE_CHANGED}:
+ * integer containing the thermal event type for the zone.
+ */
+ public static final String EXTRA_EVENT = "event";
+
+ /**
+ * Extra for {@link ACTION_THERMAL_ZONE_STATE_CHANGED}:
+ * integer containing the temperature of the zone.
+ */
+ public static final String EXTRA_TEMP = "temp";
+ public static final String ACTION_CHANGE_THERMAL_PROFILE =
+ "android.intent.action.CHANGE_THERMAL_PROFILE";
+ /**
+ * Extra for {@link ACTION_THERMAL_ZONE_STATE_CHANGED}:
+ * String containing the name of the zone.
+ */
+ public static final String EXTRA_NAME = "name";
+ public static final String EXTRA_PROFILE = "Profile";
+
+ private static Intent sQueryProfileIntent;
+ public static final String ACTION_QUERY_THERMAL_PROFILE =
+ "com.intel.thermal.action.QUERY_THERMAL_PROFILE";
+ public static final String ACTION_KILL = "kill";
+
+ /**
+ * Integer containing the number of thermal profiles.
+ */
+ public static final String EXTRA_NUM_PROFILE = "NumProfiles";
+ /**
+ * Space separated string containing list of thermal profile names.
+ */
+ public static final String EXTRA_PROFILE_LIST = "ProfileList";
+ /**
+ * String containing current thermal profile name.
+ */
+ public static final String EXTRA_CUR_PROFILE = "CurProfile";
+
+ /* values for "STATE" field in the THERMAL_STATE_CHANGED Intent */
+ public static final int THERMAL_STATE_OFF = -1;
+
+ public static final int THERMAL_STATE_NORMAL = 0;
+
+ public static final int THERMAL_STATE_WARNING = 1;
+
+ public static final int THERMAL_STATE_ALERT = 2;
+
+ public static final int THERMAL_STATE_CRITICAL = 3;
+
+ public static final int DEFAULT_NUM_THROTTLE_VALUES = 4;
+
+ // 5 including TOFF and TCRITICAL
+ public static final int DEFAULT_NUM_ZONE_STATES = 5;
+
+ public static final String STATE_NAMES[] = {
+ "OFF", "NORMAL", "WARNING", "ALERT", "CRITICAL"
+ };
+
+ /* values of the "EVENT" field in the THERMAL_STATE_CHANGED intent */
+ /* Indicates type of event */
+ public static final int THERMAL_LOW_EVENT = 0;
+
+ public static final int THERMAL_HIGH_EVENT = 1;
+
+ public static final int THERMAL_EMUL_TEMP_EVENT = 2;
+
+ public static final int INVALID_TEMP = 0xDEADBEEF;
+
+ /* base sysfs path for sensors */
+ public static final String sSysfsSensorBasePath = "/sys/class/thermal/thermal_zone";
+
+ public static final String sSysfsSensorHighTempPath = "trip_point_1_temp";
+
+ public static final String sSysfsSensorLowTempPath = "trip_point_0_temp";
+
+ public static final String sCoolingDeviceBasePath = "/sys/class/thermal/cooling_device";
+
+ public static final String sCoolingDeviceState = "/cur_state";
+
+ public static final int THROTTLE_MASK_ENABLE = 1;
+
+ public static final int DETHROTTLE_MASK_ENABLE = 1;
+
+ /**
+ * Magic number (agreed upon between the Thermal driver and the Thermal Service)
+ * symbolising Dynamic Turbo OFF
+ */
+ public static final int DISABLE_DYNAMIC_TURBO = 0xB0FF;
+
+ public static boolean sIsDynamicTurboEnabled = false;
+
+ /* thermal notifier system properties for shutdown action */
+ public static boolean sShutdownTone = false;
+
+ public static boolean sShutdownToast = false;
+
+ public static boolean sShutdownVibra = false;
+
+ /* Name of default Thermal Profile */
+ public static final String DEFAULT_PROFILE_NAME = "Default";
+
+ /* Lock protecting profile-switch */
+ private static final Object sProfileSwitchLock = new Object();
+
+ /**
+ * This class stores the zone throttle info. It contains the zoneID,
+ * CriticalShutdown flag and CoolingDeviceInfo arraylist.
+ */
+ public static class ZoneCoolerBindingInfo {
+ private int mZoneID;
+ // max states includes TOFF also.
+ // if user provides k threshold values in XML.
+ // mMaxStates = k + 1(for critical) + 1(for TOFF)
+ // this is same as the max states stored in corresponding zone object
+ protected int mMaxStates;
+ private int mIsCriticalActionShutdown;
+
+ /* cooler ID mask, 1 - throttle device, 0- no action, -1- dont care */
+ private ArrayList<CoolingDeviceInfo> mCoolingDeviceInfoList = null;
+
+ // ManyToOneMapping: ZoneStates >= CoolingDeviceStates
+ private ArrayList<Integer> mZoneToCoolDevBucketSize = null;
+
+ // OneToOneMapping: CoolingDeviceStates >= ThrottleValues
+ private ArrayList<Integer> mCoolDevToThrottBucketSize = null;
+
+ private CoolingDeviceInfo lastCoolingDevInfoInstance = null;
+
+ public ZoneCoolerBindingInfo() {
+ mZoneToCoolDevBucketSize = new ArrayList<Integer>();
+ mCoolDevToThrottBucketSize = new ArrayList<Integer>();
+ }
+
+ public int getLastState() {
+ // mMaxStates = k + 1(for critical) + 1(for TOFF)
+ return mMaxStates - 2;
+ }
+
+ public void setMaxStates(int state) {
+ mMaxStates = state;
+ }
+
+ public int getMaxStates() {
+ return mMaxStates;
+ }
+
+ public void setZoneToCoolDevBucketSize() {
+ int size = 1;
+ int zoneStates = getMaxStates();
+ for (CoolingDeviceInfo coolDev : mCoolingDeviceInfoList) {
+ size = (zoneStates - 1) / coolDev.getCoolingDeviceStates();
+ mZoneToCoolDevBucketSize.add(size == 0 ? 1 : size);
+ }
+ }
+
+ public int getZoneToCoolDevBucketSizeIndex(int index) {
+ if (mZoneToCoolDevBucketSize.size() > index)
+ return mZoneToCoolDevBucketSize.get(index);
+
+ return 1;
+ }
+
+ public int getCoolDevToThrottBucketSizeIndex(int index) {
+ if (mZoneToCoolDevBucketSize.size() > index)
+ return mCoolDevToThrottBucketSize.get(index);
+
+ return 1;
+ }
+
+ public void setCoolDevToThrottBucketSize() {
+ int size = 1;
+ for (CoolingDeviceInfo coolDev : mCoolingDeviceInfoList) {
+ size = coolDev.getMaxThrottleStates() / coolDev.getCoolingDeviceStates();
+ mCoolDevToThrottBucketSize.add(size == 0 ? 1 : size);
+ }
+ }
+
+ public void printAttributes() {
+ if (mCoolingDeviceInfoList == null) return;
+ StringBuilder s = new StringBuilder();
+ for (CoolingDeviceInfo c : mCoolingDeviceInfoList) {
+ if (c != null) {
+ s.append(c.getCoolingDeviceId());
+ s.append(",");
+ }
+ }
+ Log.i(TAG, "zone id:" + mZoneID + " coolingDevID mapped:" + s.toString());
+ }
+
+ public void printMappedAttributes() {
+ if (mZoneToCoolDevBucketSize == null || mCoolDevToThrottBucketSize == null) return;
+ StringBuilder s = new StringBuilder();
+ for (int bs : mZoneToCoolDevBucketSize) {
+ s.append(bs);
+ s.append(",");
+ }
+ Log.i(TAG, "zone id:" + mZoneID + " ZoneToCoolDevBucketSize:" + s.toString());
+ // clear the string
+ s.delete(0,s.length());
+ for (int bs : mCoolDevToThrottBucketSize) {
+ s.append(bs);
+ s.append(",");
+ }
+ Log.i(TAG, "zone id:" + mZoneID + " CoolDevToThrottBucketSize:" + s.toString());
+ }
+
+ public class CoolingDeviceInfo {
+ private int mCDeviceID;
+
+ // mCoolingDeviceState is number of device states exposed under a zone.
+ // this must be less than or equal to its total number of throttle values
+ private int mCoolingDeviceStates = DEFAULT_NUM_THROTTLE_VALUES;
+
+ // store a copy here for fast lookup during throttling/dethrottling
+ private int mMaxThrottleStates = 0;
+ private ArrayList<Integer> mDeviceThrottleMask = null;
+
+ private ArrayList<Integer> mDeviceDethrottleMask = null;
+
+ public CoolingDeviceInfo() {
+ }
+
+ public int getMaxThrottleStates() {
+ return mMaxThrottleStates;
+ }
+
+ public boolean checkMaskList(int throttleStates) {
+ boolean ret = true;
+ // if the list is empty this mean, THROTTLE MASK and/or
+ // DETHTOTTLE mask was not provided. Initialize default mask.
+ if (mDeviceThrottleMask == null) {
+ mDeviceThrottleMask = new ArrayList<Integer>();
+ for (int i = 0; i < mCoolingDeviceStates; i++) {
+ mDeviceThrottleMask.add(THROTTLE_MASK_ENABLE);
+ }
+ } else if (mDeviceThrottleMask.size() != mCoolingDeviceStates) {
+ Log.i(TAG, "cdevid:" + mCDeviceID
+ + " has mismatch in Cooling device state and mask array!deactivate!");
+ ret = false;
+ }
+
+ if (mDeviceDethrottleMask == null) {
+ mDeviceDethrottleMask = new ArrayList<Integer>();
+ for (int i = 0; i < mCoolingDeviceStates; i++) {
+ mDeviceDethrottleMask.add(DETHROTTLE_MASK_ENABLE);
+ }
+ } else if (mDeviceDethrottleMask.size() != mCoolingDeviceStates) {
+ Log.i(TAG, "cdevid:" + mCDeviceID
+ + " has mismatch in Cooling device state and mask array!deactivate!");
+ ret = false;
+ }
+ if (ret) {
+ mMaxThrottleStates = throttleStates;
+ }
+ return ret;
+ }
+
+ public int getCoolingDeviceId() {
+ return mCDeviceID;
+ }
+
+ public void setCoolingDeviceId(int deviceID) {
+ mCDeviceID = deviceID;
+ }
+
+ public int getCoolingDeviceStates() {
+ return mCoolingDeviceStates;
+ }
+
+ public void setCoolingDeviceStates(int num) {
+ mCoolingDeviceStates = num;
+ }
+
+ public ArrayList<Integer> getThrottleMaskList() {
+ return mDeviceThrottleMask;
+ }
+
+ public ArrayList<Integer> getDeThrottleMaskList() {
+ return mDeviceDethrottleMask;
+ }
+
+ public void setThrottleMaskList(ArrayList<Integer> list) {
+ this.mDeviceThrottleMask = list;
+ }
+
+ public void setDeThrottleMaskList(ArrayList<Integer> list) {
+ this.mDeviceDethrottleMask = list;
+ }
+
+ }
+
+ public ArrayList<CoolingDeviceInfo> getCoolingDeviceInfoList() {
+ return mCoolingDeviceInfoList;
+ }
+
+ public void createNewCoolingDeviceInstance() {
+ lastCoolingDevInfoInstance = new CoolingDeviceInfo();
+ }
+
+ public CoolingDeviceInfo getLastCoolingDeviceInstance() {
+ return lastCoolingDevInfoInstance;
+ }
+
+ public void setZoneID(int zoneID) {
+ mZoneID = zoneID;
+ }
+
+ public int getZoneID() {
+ return mZoneID;
+ }
+
+ public void setCriticalActionShutdown(int val) {
+ mIsCriticalActionShutdown = val;
+ }
+
+ public int getCriticalActionShutdown() {
+ return mIsCriticalActionShutdown;
+ }
+
+ public void setCoolingDeviceInfoList(ArrayList<CoolingDeviceInfo> devinfoList) {
+ mCoolingDeviceInfoList = devinfoList;
+ }
+
+ public void initializeCoolingDeviceInfoList() {
+ mCoolingDeviceInfoList = new ArrayList<CoolingDeviceInfo>();
+ }
+
+ public void addCoolingDeviceToList(CoolingDeviceInfo CdeviceInfo) {
+ mCoolingDeviceInfoList.add(CdeviceInfo);
+ }
+ }
+
+ /* platform information */
+ public static class PlatformInfo {
+ public int mMaxThermalStates;
+
+ public int getMaxThermalStates() {
+ return mMaxThermalStates;
+ }
+
+ public void printAttrs() {
+ Log.i(TAG, Integer.toString(mMaxThermalStates));
+ }
+ public PlatformInfo() {}
+ }
+
+ /* methods */
+ public ThermalManager() {
+ // empty constructor
+ }
+
+ public static void setContext(Context context) {
+ sContext = context;
+ }
+
+ public static String getVersion() {
+ return sVersion;
+ }
+
+ public static void loadiTUXVersion() {
+ sVersion = SystemProperties.get(ITUX_VERSION_PROPERTY, "none");
+ if (sVersion.equalsIgnoreCase("none")) {
+ Log.i(TAG, "iTUX Version not found!");
+ } else {
+ Log.i(TAG, "iTUX Version:" + sVersion);
+ }
+ }
+
+ public static void addThermalEvent(ThermalEvent event) {
+ try {
+ ThermalManager.sEventQueue.put(event);
+ } catch (InterruptedException ex) {
+ Log.i(TAG, "caught InterruptedException in posting to event queue");
+ }
+ }
+
+ public static void setCurBindMap(String profName) {
+ synchronized (sProfileSwitchLock) {
+ sZoneCoolerBindMap = sProfileBindMap.get(profName);
+ }
+ }
+
+ public static Hashtable<Integer, ZoneCoolerBindingInfo> getCurBindMap() {
+ synchronized (sProfileSwitchLock) {
+ return sZoneCoolerBindMap;
+ }
+ }
+
+ public static Hashtable<Integer, ZoneCoolerBindingInfo> getBindMap(String profName) {
+ return sProfileBindMap.get(profName);
+ }
+
+ private static void setCurProfileName(String profName) {
+ sCurProfileName = profName;
+ }
+
+ public static String getCurProfileName() {
+ return sCurProfileName;
+ }
+
+ private static boolean isProfileExists(String profName) {
+ if (sProfileZoneMap.get(profName) == null || sProfileBindMap.get(profName) == null) {
+ return false;
+ }
+ return true;
+ }
+
+ private static void startNewProfile(String profName) {
+ sThermalZonesList = sProfileZoneMap.get(profName);
+ sZoneCoolerBindMap = sProfileBindMap.get(profName);
+ if (sThermalZonesList == null || sZoneCoolerBindMap == null) {
+ Log.i(TAG, "Couldn't shift to profile:" + profName);
+ return;
+ }
+ initializeZoneCriticalPendingMap();
+ setCurProfileName(profName);
+ int activeZones = startMonitoringZones();
+ Log.i(TAG, activeZones + " zones found active in profile " + profName);
+ // broadcast a sticky intent for the clients
+ sendQueryProfileIntent();
+ }
+
+ public static void stopCurrentProfile() {
+ for (ThermalZone zone : sThermalZonesList) {
+ // Stop Polling threads
+ zone.stopMonitoring();
+ // Unregister UEvent/EmulTemp observers
+ zone.unregisterReceiver();
+ // Reset Parameters:
+ // Zone State: Normal, Event Type: LOW, Temperature: Normal Threshold
+ zone.setZoneState(0);
+ zone.setEventType(ThermalManager.THERMAL_LOW_EVENT);
+ zone.setZoneTemp(zone.getZoneTempThreshold(0));
+ // Send ThermalIntent with above parameters
+ // This will release all throttle controls this zone had.
+ // Since we are in the middle of a profile switch(stop),
+ // set the override parameter as true, so that this
+ // event is actually queued for processing.
+ // TODO: Find a way to take care of zones that are not
+ // present in thermal_sensor_config.xml but present in
+ // thermal_throttle_config.xml (usually from other components)
+ zone.sendThermalEvent();
+ // Reprogram the sensor thresholds if this zone supported interrupts
+ // TODO: We are reprogramming the calibrated thresholds in case the
+ // the sensor was using 'weights' and 'offset'. Hope this is fine.
+ if (zone.isUEventSupported()) {
+ zone.programThresholds((zone.getThermalSensorList()).get(0));
+ }
+ }
+ }
+
+ public static void startDefaultProfile() {
+ if (isProfileExists(DEFAULT_PROFILE_NAME)) {
+ startNewProfile(DEFAULT_PROFILE_NAME);
+ }
+ // register for Thermal Profile Change Intent only after
+ // we have started the default profile
+ sCoolingManager.registerProfChangeListener();
+ }
+
+ public static void changeThermalProfile(String newProfName) {
+ synchronized (sProfileSwitchLock) {
+ if (newProfName.equalsIgnoreCase(sCurProfileName)) {
+ Log.i(TAG, "New Profile same as current profile. Profile change request Ignored");
+ return;
+ }
+ if (!isProfileExists(newProfName)) {
+ Log.i(TAG, "New Profile does not exist in xml. Profile change request Ignored");
+ return;
+ }
+ Log.i(TAG, "ACTION_CHANGE_THERMAL_PROFILE received. New Profile: " + newProfName);
+
+ stopCurrentProfile();
+ startNewProfile(newProfName);
+ }
+ }
+
+ public static void setBucketSizeForProfiles() {
+ Iterator it = ThermalManager.sProfileZoneMap.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry entryProfZone = (Map.Entry) it.next();
+ String keyProfile = (String) entryProfZone.getKey();
+ sThermalZonesList = (ArrayList<ThermalZone>) entryProfZone.getValue();
+ setCurBindMap(keyProfile);
+ for (ThermalZone zone : sThermalZonesList) {
+ if (sZoneCoolerBindMap == null) {
+ Log.e(TAG, "ZoneCoolerBindMap null while setBucketSizeForProfiles");
+ return;
+ }
+ ZoneCoolerBindingInfo bindInfo = sZoneCoolerBindMap.get(zone.getZoneId());
+ if (bindInfo == null) {
+ Log.e(TAG, "CoolerBindingInfo for zoneid:" + zone.getZoneId() + "not mapped");
+ return;
+ }
+ bindInfo.setMaxStates(zone.getMaxStates());
+ bindInfo.setZoneToCoolDevBucketSize();
+ bindInfo.setCoolDevToThrottBucketSize();
+ if (zone.isUEventSupported()) {
+ // calibration of thresholds based on weight, order
+ if (!zone.isMaxThreshExceed())
+ zone.calibrateThresholds();
+ }
+ }
+ }
+ }
+
+ public static int startMonitoringZones() {
+ int activeZonesCount = 0;
+ for (ThermalZone zone : sThermalZonesList) {
+ zone.computeZoneActiveStatus();
+ if (zone.getZoneActiveStatus() == false) {
+ Log.i(TAG, "deactivating inactive zone:" + zone.getZoneName());
+ continue;
+ }
+
+ ZoneCoolerBindingInfo bindInfo = sZoneCoolerBindMap.get(zone.getZoneId());
+ if (bindInfo != null) {
+ // TODO: To be conditioned under debug
+ bindInfo.printMappedAttributes();
+ }
+ if (zone.isUEventSupported()) {
+ zone.registerUevent();
+ } else {
+ // start polling thread for each zone
+ zone.startMonitoring();
+ }
+ zone.startEmulTempObserver();
+ activeZonesCount++;
+ }
+ return activeZonesCount;
+ }
+
+ public static void readShutdownNotiferProperties() {
+ try {
+ if ("1".equals(SystemProperties.get("persist.thermal.shutdown.msg", "0"))) {
+ sShutdownToast = true;
+ }
+ if ("1".equals(SystemProperties.get("persist.thermal.shutdown.tone", "0"))) {
+ sShutdownTone = true;
+ }
+ if ("1".equals(SystemProperties.get("persist.thermal.shutdown.vibra", "0"))) {
+ sShutdownVibra = true;
+ }
+ } catch (java.lang.IllegalArgumentException e) {
+ Log.e(TAG, "exception caught in reading thermal system properties");
+ }
+ }
+
+ private static void initializeZoneCriticalPendingMap() {
+ sZoneCriticalPendingMap = new Hashtable<Integer, Integer>();
+ if (sZoneCriticalPendingMap == null) return;
+ Enumeration en;
+ try {
+ // look up for zone list is performed from sZoneCoolerBindMap instead of
+ // sThermalZonesList since some non thermal zones may not have entry in
+ // sThermalZonesList. This is because such zones only have entry in throttle
+ // config file and not in sensor config files.
+ // 'sZoneCoolerBindMap' is protected by caller here.
+ en = sZoneCoolerBindMap.keys();
+ while (en.hasMoreElements()) {
+ int zone = (Integer) en.nextElement();
+ sZoneCriticalPendingMap.put(zone, CRITICAL_FALSE);
+ }
+ } catch (NoSuchElementException e) {
+ Log.i(TAG, "NoSuchElementException in InitializeZoneCriticalPendingMap()");
+ }
+ }
+
+ /*
+ * updateZoneCriticalPendingMap updates sZoneCriticalPendingMap synchronously.
+ * sCriticalZonesCount is incremented iff old value in the map for the zone is
+ * FALSE (ensures count is incremented only once for a zone) and decremented
+ * iff oldval is TRUE (ensures no negative value for count)
+ **/
+ public static boolean updateZoneCriticalPendingMap(int zoneid, int flag) {
+ synchronized (sCriticalPendingLock) {
+ if (sZoneCriticalPendingMap == null) return false;
+ Integer oldVal = sZoneCriticalPendingMap.get(zoneid);
+ if (oldVal == null) return false;
+ sZoneCriticalPendingMap.put(zoneid, flag);
+ if (oldVal == CRITICAL_FALSE && flag == CRITICAL_TRUE) {
+ sCriticalZonesCount++;
+ } else if (oldVal == CRITICAL_TRUE && flag == CRITICAL_FALSE) {
+ sCriticalZonesCount--;
+ }
+ return true;
+ }
+ }
+
+ public static boolean checkShutdownCondition() {
+ synchronized (sCriticalPendingLock) {
+ return sCriticalZonesCount > 0;
+ }
+ }
+
+ public static ThermalSensor getSensor(String sensorName) {
+ if (sensorName == null || sSensorMap == null) return null;
+ return sSensorMap.get(sensorName);
+ }
+
+ public static void buildProfileNameList() {
+ int count = 0;
+ StringBuilder s = new StringBuilder();
+ Iterator it = sProfileZoneMap.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry entry = (Map.Entry) it.next();
+ String key = (String) entry.getKey();
+ // create list of only valid profiles
+ if (isProfileExists(key)) {
+ // build a space seperate list of string
+ s.append(key);
+ s.append(" ");
+ count++;
+ }
+ }
+
+ sProfileNameList = s.toString();
+ sProfileCount = count;
+ Log.i(TAG, "profile name list:" + sProfileNameList);
+ Log.i(TAG, "profile count:" + sProfileCount);
+ }
+
+ public static void initializeStickyIntent() {
+ sQueryProfileIntent = new Intent();
+ sQueryProfileIntent.setAction(ACTION_QUERY_THERMAL_PROFILE);
+ }
+
+ private static void sendQueryProfileIntent() {
+ if (sQueryProfileIntent != null && sContext != null) {
+ sQueryProfileIntent.putExtra(ThermalManager.EXTRA_NUM_PROFILE, sProfileCount);
+ sQueryProfileIntent.putExtra(ThermalManager.EXTRA_PROFILE_LIST, sProfileNameList);
+ sQueryProfileIntent.putExtra(ThermalManager.EXTRA_CUR_PROFILE, sCurProfileName);
+ sContext.sendStickyBroadcastAsUser(sQueryProfileIntent, UserHandle.ALL);
+ }
+ }
+
+ public static void clearData() {
+ sThermalZonesList.clear();
+ // clearing hastables
+ sProfileZoneMap.clear();
+ sZoneCoolerBindMap.clear();
+ sProfileBindMap.clear();
+ sCDevMap.clear();
+ sSensorMap.clear();
+ sZoneCriticalPendingMap.clear();
+ }
+}
diff --git a/ituxd/src/com/intel/thermal/ThermalSensor.java b/ituxd/src/com/intel/thermal/ThermalSensor.java
new file mode 100644
index 0000000..78c7739
--- /dev/null
+++ b/ituxd/src/com/intel/thermal/ThermalSensor.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2014 Intel Corporation All Rights Reserved.
+ *
+ * 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.
+ */
+
+package com.intel.thermal;
+
+import com.intel.thermal.ThermalManager;
+
+import android.util.Log;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * The ThermalSensor class describes the attributes of a Thermal Sensor. This
+ * class implements methods that retrieve temperature sensor information from
+ * the kernel through the native interface.
+ *
+ * @hide
+ */
+public class ThermalSensor {
+
+ private static final String TAG = "ThermalSensor";
+ private String mSensorPath; /* sys path to read temp from */
+ private String mSensorName; /* name of the sensor */
+ private String mInputTempPath; /* sys path to read the current temp */
+ private String mHighTempPath; /* sys path to set the intermediate upper threshold */
+ private String mLowTempPath; /* sys path to set the intermediate lower threshold */
+ private String mUEventDevPath; /* sys path for uevent listener */
+ private int mErrorCorrectionTemp; /* Temperature difference in mC */
+ private int mSensorID = -1;
+ private int mSensorState; /* Thermal state of the sensor */
+ private int mCurrTemp; /* Holds the latest temperature of the sensor */
+ private int mSensorSysfsIndx; /* Index of this sensor in the sysfs */
+ private boolean mIsSensorActive = false; /* Whether this sensor is active */
+
+ public void printAttrs() {
+ Log.i(TAG, "mSensorName: " + mSensorName);
+ Log.i(TAG, "mSensorPath: " + mSensorPath);
+ Log.i(TAG, "mInputTempPath: " + mInputTempPath);
+ Log.i(TAG, "mHighTempPath: " + mHighTempPath);
+ Log.i(TAG, "mLowTempPath: " + mLowTempPath);
+ Log.i(TAG, "mUEventDevPath: " + mUEventDevPath);
+ Log.i(TAG, "mErrorCorrection: " + mErrorCorrectionTemp);
+ }
+
+ private void setSensorSysfsPath() {
+ int indx = ThermalUtils.getThermalZoneIndex(mSensorName);
+ // The battery subsystem exposes sensors under different names.
+ // The only commonality among them is that all of them contain
+ // the string "battery".
+ if (indx == -1 && mSensorName.contains("battery")) {
+ indx = ThermalUtils.getThermalZoneIndexContains("battery");
+ }
+
+ if (indx != -1) {
+ mSensorPath = ThermalManager.sSysfsSensorBasePath + indx + "/";
+ }
+
+ mSensorSysfsIndx = indx;
+ }
+
+ public boolean getSensorActiveStatus() {
+ return mIsSensorActive;
+ }
+
+ public String getSensorSysfsPath() {
+ return mSensorPath;
+ }
+
+ public ThermalSensor() {
+ mSensorState = ThermalManager.THERMAL_STATE_OFF;
+ mCurrTemp = ThermalManager.INVALID_TEMP;
+ mSensorPath = "auto";
+ mInputTempPath = "auto";
+ mHighTempPath = "auto";
+ mLowTempPath = "auto";
+ mUEventDevPath = "auto";
+
+ // Set default value of 'correction temperature' to 1000mC
+ mErrorCorrectionTemp = 1000;
+ }
+
+ public int getSensorID() {
+ return mSensorID;
+ }
+
+ public int getSensorSysfsIndx() {
+ return mSensorSysfsIndx;
+ }
+
+ public String getSensorPath() {
+ return mSensorPath;
+ }
+
+ /**
+ * This function sets the sensor path to the given String value. If the
+ * String is "auto" it loops through the standard sysfs path, to obtain the
+ * 'mSensorPath'. The standard sysfs path is /sys/class/
+ * thermal/thermal_zoneX and the look up is based on 'mSensorName'.
+ * If sensor path is "none", sensor temp is not read via any sysfs
+ */
+ public void setSensorPath(String path) {
+ if (path.equalsIgnoreCase("auto")) {
+ setSensorSysfsPath();
+ } else {
+ mSensorPath = path;
+ }
+ }
+
+ private boolean isSensorSysfsValid(String path) {
+ return ThermalUtils.isFileExists(path);
+ }
+
+ public String getSensorName() {
+ return mSensorName;
+ }
+
+ public void setSensorName(String name) {
+ mSensorName = name;
+ }
+
+ public void setUEventDevPath(String devPath) {
+ mUEventDevPath = devPath;
+ }
+
+ public String getUEventDevPath() {
+ return mUEventDevPath;
+ }
+
+ public void setErrorCorrectionTemp(int temp) {
+ mErrorCorrectionTemp = temp;
+ }
+
+ public int getErrorCorrectionTemp() {
+ return mErrorCorrectionTemp;
+ }
+
+
+ public void setInputTempPath(String name) {
+ // sensor path is none, it means sensor temperature reporting is
+ // not sysfs based. So turn sensor active by default.
+ // If the sensor path does not exist, deactivate the sensor.
+ if (mSensorPath != null && mSensorPath.equalsIgnoreCase("none")) {
+ mIsSensorActive = true;
+ } else {
+ if (name != null && name.equalsIgnoreCase("auto")) {
+ name = "temp";
+ }
+ mInputTempPath = mSensorPath + name;
+ if (!isSensorSysfsValid(mInputTempPath)) {
+ mIsSensorActive = false;
+ Log.i(TAG, "Sensor:" + mSensorName + " path:" + mInputTempPath
+ + " is invalid...deactivaing Sensor");
+ } else {
+ mIsSensorActive = true;
+ }
+ }
+ }
+
+ public String getSensorInputTempPath() {
+ return mInputTempPath;
+ }
+
+ public void setHighTempPath(String name) {
+ if (name != null && name.equalsIgnoreCase("auto")) {
+ mHighTempPath = mSensorPath + ThermalManager.sSysfsSensorHighTempPath;
+ } else {
+ if (mSensorPath != null && mSensorPath.equalsIgnoreCase("none")) {
+ mHighTempPath = "invalid";
+ } else {
+ mHighTempPath = mSensorPath + name;
+ }
+ }
+ }
+
+ public String getSensorHighTempPath() {
+ return mHighTempPath;
+ }
+
+ public void setLowTempPath(String name) {
+ if (name != null && name.equalsIgnoreCase("auto")) {
+ mLowTempPath = mSensorPath + ThermalManager.sSysfsSensorLowTempPath;
+ } else {
+ if (mSensorPath != null && mSensorPath.equalsIgnoreCase("none")) {
+ mLowTempPath = "invalid";
+ } else {
+ mLowTempPath = mSensorPath + name;
+ }
+ }
+ }
+
+ public String getSensorLowTempPath() {
+ return mLowTempPath;
+ }
+
+ public void setCurrTemp(int temp) {
+ mCurrTemp = temp;
+ }
+
+ public int getCurrTemp() {
+ return mCurrTemp;
+ }
+
+ /**
+ * Method that actually does a Sysfs read.
+ */
+ public int readSensorTemp() {
+ int val = ThermalManager.INVALID_TEMP;
+ try {
+ String tempStr = ThermalUtils.readSysfs(mInputTempPath);
+ if (tempStr != null) {
+ val = Integer.parseInt(tempStr.trim());
+ }
+ } catch (NumberFormatException e) {
+ Log.i(TAG, "NumberFormatException in readSensorTemp():" + mInputTempPath);
+ }
+ return val;
+ }
+
+ /**
+ * Method to read the current temperature from sensor. This method should be
+ * used only when we want to obtain the latest temperature from sensors.
+ * Otherwise, the getCurrTemp method should be used, which returns the
+ * previously read value.
+ */
+ public void updateSensorTemp() {
+ int val = readSensorTemp();
+ if (val != ThermalManager.INVALID_TEMP) {
+ setCurrTemp(val);
+ }
+ }
+
+ public int getSensorThermalState() {
+ return mSensorState;
+ }
+
+ public void setSensorThermalState(int state) {
+ mSensorState = state;
+ }
+
+ public void setAutoValues() {
+ if (mSensorPath.equalsIgnoreCase("auto")) {
+ setSensorPath(mSensorPath);
+ }
+ if (mInputTempPath.equalsIgnoreCase("auto")) {
+ setInputTempPath(mInputTempPath);
+ }
+ if (mHighTempPath.equalsIgnoreCase("auto")) {
+ setHighTempPath(mHighTempPath);
+ }
+ if (mLowTempPath.equalsIgnoreCase("auto")) {
+ setLowTempPath(mLowTempPath);
+ }
+ if (mUEventDevPath.equalsIgnoreCase("auto")) {
+ // build the sensor UEvent listener path
+ if (mSensorSysfsIndx == -1) {
+ mUEventDevPath = "invalid";
+ Log.i(TAG, "Cannot build UEvent path for sensor:" + mSensorName);
+ return;
+ } else {
+ mUEventDevPath = ThermalManager.sUEventDevPath + mSensorSysfsIndx;
+ }
+ } else if (!mUEventDevPath.contains("DEVPATH=")) {
+ mUEventDevPath = "DEVPATH=" + mUEventDevPath;
+ }
+ }
+
+}
diff --git a/ituxd/src/com/intel/thermal/ThermalSensorAttrib.java b/ituxd/src/com/intel/thermal/ThermalSensorAttrib.java
new file mode 100644
index 0000000..37fbc81
--- /dev/null
+++ b/ituxd/src/com/intel/thermal/ThermalSensorAttrib.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014 Intel Corporation All Rights Reserved.
+ *
+ * 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.
+ */
+
+package com.intel.thermal;
+
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * The ThermalSensorAttrib class describes the attributes of a Thermal Sensor that are
+ * zone specific.
+ * @hide
+ */
+public class ThermalSensorAttrib {
+
+ private static final String TAG = "ThermalSensorAttrib";
+ private String mSensorName;
+ private Integer mWeights[];
+ private Integer mOrder[];
+
+ public String getSensorName() {
+ return mSensorName;
+ }
+
+ public void setSensorName(String name) {
+ mSensorName = name;
+ }
+
+ public Integer[] getWeights() {
+ return mWeights;
+ }
+
+ public void setWeights(ArrayList<Integer> list) {
+ if (list != null) {
+ mWeights = new Integer[list.size()];
+ if (mWeights != null) {
+ mWeights = list.toArray(mWeights);
+ }
+ }
+ }
+
+ public Integer[] getOrder() {
+ return mOrder;
+ }
+
+ public void setOrder(ArrayList<Integer> list) {
+ if (list != null) {
+ mOrder = new Integer[list.size()];
+ if (mOrder != null) {
+ mOrder = list.toArray(mOrder);
+ }
+ }
+ }
+
+ public void printAttrs() {
+ Log.i(TAG, "SensorAttrib: " + mSensorName);
+ Log.i(TAG, "mWeights[]: " + Arrays.toString(mWeights));
+ Log.i(TAG, "mOrder[]: " + Arrays.toString(mOrder));
+ if (mWeights != null && mOrder != null && mWeights.length != mOrder.length) {
+ Log.i(TAG, "mismatch in weights and order array, raw sensor temp will be used");
+ }
+ }
+}
diff --git a/ituxd/src/com/intel/thermal/ThermalService.java b/ituxd/src/com/intel/thermal/ThermalService.java
new file mode 100644
index 0000000..0751885
--- /dev/null
+++ b/ituxd/src/com/intel/thermal/ThermalService.java
@@ -0,0 +1,602 @@
+/*
+ * Copyright 2014 Intel Corporation All Rights Reserved.
+ *
+ * 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.
+ */
+
+package com.intel.thermal;
+
+import android.app.ActivityManagerNative;
+import android.app.IntentService;
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.ClassLoader;
+import java.lang.NullPointerException;
+import java.lang.reflect.Array;
+import java.lang.SecurityException;
+import java.util.ArrayList;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+/**
+ * The ThermalService monitors the Thermal zones on the platform.
+ * The number of thermal zones and sensors associated with the zones are
+ * obtained from the thermal_sensor_config.xml file. When any thermal zone
+ * crosses the thresholds configured in the xml, a Thermal Intent is sent.
+ * ACTION_THERMAL_ZONE_STATE_CHANGED
+ * The Thermal Cooling Manager acts upon this intent and throttles
+ * the corresponding cooling device.
+ *
+ * @hide
+ */
+public class ThermalService extends Service {
+ private static final String TAG = ThermalService.class.getSimpleName();
+ private static Context mContext;
+ private Handler mHandler = new Handler();
+ static {
+ System.loadLibrary("thermalJNI");
+ }
+ protected enum MetaTag {
+ ENUM_UNKNOWN,
+ ENUM_ZONETHRESHOLD,
+ ENUM_POLLDELAY,
+ ENUM_MOVINGAVGWINDOW
+ }
+
+ public class ThermalParser {
+ // Names of the XML Tags
+ private static final String PINFO = "PlatformInfo";
+ private static final String SENSOR_ATTRIB = "SensorAttrib";
+ private static final String SENSOR = "Sensor";
+ private static final String ZONE = "Zone";
+ private static final String THERMAL_CONFIG = "thermalconfig";
+ private static final String THRESHOLD = "Threshold";
+ private static final String POLLDELAY = "PollDelay";
+ private static final String MOVINGAVGWINDOW = "MovingAverageWindow";
+ private static final String ZONELOGIC = "ZoneLogic";
+ private static final String WEIGHT = "Weight";
+ private static final String ORDER = "Order";
+ private static final String OFFSET = "Offset";
+ private static final String ZONETHRESHOLD = "ZoneThreshold";
+ private static final String PROFILE = "Profile";
+
+ private boolean mDone = false;
+ private ThermalManager.PlatformInfo mPlatformInfo = null;
+ private ThermalSensor mCurrSensor = null;
+ private ThermalZone mCurrZone = null;
+ private ArrayList<ThermalSensorAttrib> mCurrSensorAttribList = null;
+ private ThermalSensorAttrib mCurrSensorAttrib = null;
+ private ArrayList<ThermalZone> mThermalZones = null;
+ private ArrayList<Integer> mPollDelayList = null;
+ private ArrayList<Integer> mMovingAvgWindowList = null;
+ private ArrayList<Integer> mWeightList = null;
+ private ArrayList<Integer> mOrderList = null;
+ private ArrayList<Integer> mZoneThresholdList = null;
+ private String mSensorName = null;
+ XmlPullParserFactory mFactory = null;
+ XmlPullParser mParser = null;
+ int mTempZoneId = -1;
+ int mNumProfiles = 0;
+ String mTempZoneName = null;
+ String mCurProfileName = ThermalManager.DEFAULT_PROFILE_NAME;
+ FileReader mInputStream = null;
+
+ ThermalParser(String fname) {
+ try {
+ mFactory = XmlPullParserFactory.newInstance(System.
+ getProperty(XmlPullParserFactory.PROPERTY_NAME), null);
+ mFactory.setNamespaceAware(true);
+ mParser = mFactory.newPullParser();
+ } catch (SecurityException e) {
+ Log.e(TAG, "SecurityException caught in ThermalParser");
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "IllegalArgumentException caught in ThermalParser");
+ } catch (XmlPullParserException xppe) {
+ Log.e(TAG, "XmlPullParserException caught in ThermalParser");
+ }
+
+ try {
+ mInputStream = new FileReader(fname);
+ mPlatformInfo = null;
+ mCurrSensor = null;
+ mCurrZone = null;
+ mThermalZones = null;
+ if (mInputStream == null) return;
+ if (mParser != null) {
+ mParser.setInput(mInputStream);
+ }
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "FileNotFoundException Exception in ThermalParser()");
+ } catch (XmlPullParserException e) {
+ Log.e(TAG, "XmlPullParserException Exception in ThermalParser()");
+ }
+ }
+
+ ThermalParser() {
+ mParser = mContext.getResources().
+ getXml(ThermalManager.sSensorFileXmlId);
+ }
+
+ public ThermalManager.PlatformInfo getPlatformInfo() {
+ return mPlatformInfo;
+ }
+
+ public boolean parse() {
+ if (ThermalManager.sIsOverlays == false && mInputStream == null) return false;
+ /* if mParser is null, close any open stream before exiting */
+ if (mParser == null) {
+ try {
+ if (mInputStream != null) {
+ mInputStream.close();
+ }
+ } catch (IOException e) {
+ Log.i(TAG, "IOException caught in parse() function");
+ }
+ return false;
+ }
+
+ boolean ret = true;
+ MetaTag tag = MetaTag.ENUM_UNKNOWN;
+ try {
+ int mEventType = mParser.getEventType();
+ while (mEventType != XmlPullParser.END_DOCUMENT && !mDone) {
+ switch (mEventType) {
+ case XmlPullParser.START_DOCUMENT:
+ Log.i(TAG, "StartDocument");
+ break;
+ case XmlPullParser.START_TAG:
+ String tagName = mParser.getName();
+ boolean isMetaTag = false;
+ if (tagName != null && tagName.equalsIgnoreCase(ZONETHRESHOLD)) {
+ tag = MetaTag.ENUM_ZONETHRESHOLD;
+ isMetaTag = true;
+ } else if (tagName != null && tagName.equalsIgnoreCase(POLLDELAY)) {
+ tag = MetaTag.ENUM_POLLDELAY;
+ isMetaTag = true;
+ } else if (tagName != null
+ && tagName.equalsIgnoreCase(MOVINGAVGWINDOW)) {
+ tag = MetaTag.ENUM_MOVINGAVGWINDOW;
+ isMetaTag = true;
+ }
+ if (isMetaTag) {
+ ret = processMetaTag(tagName, tag);
+ } else {
+ ret = processStartElement(tagName);
+ }
+ if (!ret) {
+ if (mInputStream != null) mInputStream.close();
+ return false;
+ }
+ break;
+ case XmlPullParser.END_TAG:
+ processEndElement(mParser.getName());
+ break;
+ }
+ mEventType = mParser.next();
+ }
+ } catch (XmlPullParserException xppe) {
+ Log.i(TAG, "XmlPullParserException caught in parse():" + xppe.getMessage());
+ ret = false;
+ } catch (IOException e) {
+ Log.i(TAG, "IOException caught in parse():" + e.getMessage());
+ ret = false;
+ } finally {
+ try {
+ // end of parsing, close the stream
+ // close is moved here, since if there is an exception
+ // while parsing doc, input stream needs to be closed
+ if (mInputStream != null) mInputStream.close();
+ } catch (IOException e) {
+ Log.i(TAG, "IOException caught in parse() function");
+ ret = false;
+ }
+ return ret;
+ }
+ }
+
+ boolean processMetaTag(String tagName, MetaTag tagId) {
+ if (mParser == null || tagName == null || mCurrZone == null) return false;
+ ArrayList<Integer> tempList;
+ tempList = new ArrayList<Integer>();
+ // add the dummy value for TOFF now. update it once meta tag parsed
+ tempList.add(0);
+ try {
+ int eventType = mParser.next();
+ while (true) {
+ if (eventType == XmlPullParser.START_TAG) {
+ tempList.add(Integer.parseInt(mParser.nextText()));
+ } else if (eventType == XmlPullParser.END_TAG &&
+ mParser.getName().equalsIgnoreCase(tagName)) {
+ break;
+ }
+ eventType = mParser.next();
+ }
+ } catch (XmlPullParserException xppe) {
+ Log.e(TAG, "XmlPullParserException:" + xppe.getMessage());
+ return false;
+ } catch (IOException ioe) {
+ Log.e(TAG, "IOException:" + ioe.getMessage());
+ return false;
+ }
+ // now that all state values are parse, copy the value corresponding to <normal>
+ // state to TOFF and last state to CRITICAL state.
+ // now we have reached end of meta tag add this temp list to appropriate list
+ switch(tagId) {
+ case ENUM_POLLDELAY:
+ // add TOFF
+ tempList.set(0, tempList.get(1));
+ // add TCRITICAL
+ tempList.add(tempList.get(tempList.size() - 1));
+ mCurrZone.setPollDelay(tempList);
+ break;
+ case ENUM_ZONETHRESHOLD:
+ // add TCRITICAL
+ tempList.add(tempList.get(tempList.size() - 1));
+ mCurrZone.updateMaxStates(tempList.size());
+ mCurrZone.setZoneTempThreshold(tempList);
+ break;
+ case ENUM_MOVINGAVGWINDOW:
+ // add TOFF
+ tempList.set(0, tempList.get(1));
+ // add TCRITICAL
+ tempList.add(tempList.get(tempList.size() - 1));
+ mCurrZone.setMovingAvgWindow(tempList);
+ break;
+ case ENUM_UNKNOWN:
+ default:
+ break;
+ }
+ tempList = null;
+ return true;
+ }
+
+ boolean processStartElement(String name) {
+ if (name == null)
+ return false;
+ String zoneName;
+ boolean ret = true;
+ try {
+ if (name.equalsIgnoreCase(PINFO)) {
+ mPlatformInfo = new ThermalManager.PlatformInfo();
+ // Default Thermal States
+ mPlatformInfo.mMaxThermalStates = 5;
+ } else if (name.equalsIgnoreCase(PROFILE)) {
+ mNumProfiles++;
+ } else if (name.equalsIgnoreCase(SENSOR)) {
+ if (mCurrSensor == null) {
+ mCurrSensor = new ThermalSensor();
+ }
+ } else if (name.equalsIgnoreCase(SENSOR_ATTRIB)) {
+ if (mCurrSensorAttribList == null) {
+ mCurrSensorAttribList = new ArrayList<ThermalSensorAttrib>();
+ }
+ mCurrSensorAttrib = new ThermalSensorAttrib();
+ } else if (name.equalsIgnoreCase(ZONE)) {
+ if (mThermalZones == null)
+ mThermalZones = new ArrayList<ThermalZone>();
+ } else {
+ // Retrieve Platform Information
+ if (mPlatformInfo != null && name.equalsIgnoreCase("PlatformThermalStates")) {
+ mPlatformInfo.mMaxThermalStates = Integer.parseInt(mParser.nextText());
+ // Retrieve Zone Information
+ } else if (name.equalsIgnoreCase("ZoneName") && mTempZoneId != -1) {
+ mTempZoneName = mParser.nextText();
+ } else if (name.equalsIgnoreCase("Name")) {
+ mCurProfileName = mParser.nextText();
+ } else if (name.equalsIgnoreCase(ZONELOGIC) && mTempZoneId != -1
+ && mTempZoneName != null) {
+ String zoneLogic = mParser.nextText();
+ if (zoneLogic.equalsIgnoreCase("VirtualSkin")) {
+ mCurrZone = new VirtualThermalZone();
+ } else {
+ // default zone raw
+ mCurrZone = new RawThermalZone();
+ }
+ if (mCurrZone != null) {
+ mCurrZone.setZoneName(mTempZoneName);
+ mCurrZone.setZoneId(mTempZoneId);
+ mCurrZone.setZoneLogic(zoneLogic);
+ }
+ } else if (name.equalsIgnoreCase("ZoneID")) {
+ mTempZoneId = Integer.parseInt(mParser.nextText());
+ } else if (name.equalsIgnoreCase("SupportsUEvent") && mCurrZone != null)
+ mCurrZone.setSupportsUEvent(Integer.parseInt(mParser.nextText()));
+ else if (name.equalsIgnoreCase("SupportsEmulTemp") && mCurrZone != null)
+ mCurrZone.setEmulTempFlag(Integer.parseInt(mParser.nextText()));
+ else if (name.equalsIgnoreCase("DebounceInterval") && mCurrZone != null)
+ mCurrZone.setDBInterval(Integer.parseInt(mParser.nextText()));
+ else if (name.equalsIgnoreCase(POLLDELAY) && mCurrZone != null) {
+ mPollDelayList = new ArrayList<Integer>();
+ } else if (name.equalsIgnoreCase(OFFSET) && mCurrZone != null) {
+ mCurrZone.setOffset(Integer.parseInt(mParser.nextText()));
+ }
+
+ // Retrieve Sensor Information
+ else if (name.equalsIgnoreCase("SensorName")) {
+ if (mCurrSensorAttrib != null) {
+ mCurrSensorAttrib.setSensorName(mParser.nextText());
+ } else if (mCurrSensor != null) {
+ mCurrSensor.setSensorName(mParser.nextText());
+ }
+ } else if (name.equalsIgnoreCase("SensorPath") && mCurrSensor != null)
+ mCurrSensor.setSensorPath(mParser.nextText());
+ else if (name.equalsIgnoreCase("InputTemp") && mCurrSensor != null)
+ mCurrSensor.setInputTempPath(mParser.nextText());
+ else if (name.equalsIgnoreCase("HighTemp") && mCurrSensor != null)
+ mCurrSensor.setHighTempPath(mParser.nextText());
+ else if (name.equalsIgnoreCase("LowTemp") && mCurrSensor != null)
+ mCurrSensor.setLowTempPath(mParser.nextText());
+ else if (name.equalsIgnoreCase("UEventDevPath") && mCurrSensor != null)
+ mCurrSensor.setUEventDevPath(mParser.nextText());
+ else if (name.equalsIgnoreCase("ErrorCorrection") && mCurrSensor != null)
+ mCurrSensor.setErrorCorrectionTemp(Integer.parseInt(mParser.nextText()));
+ else if (name.equalsIgnoreCase(WEIGHT) && mCurrSensorAttrib != null) {
+ if (mWeightList == null) {
+ mWeightList = new ArrayList<Integer>();
+ }
+ if (mWeightList != null) {
+ mWeightList.add(Integer.parseInt(mParser.nextText()));
+ }
+ } else if (name.equalsIgnoreCase(ORDER) && mCurrSensorAttrib != null) {
+ if (mOrderList == null) {
+ mOrderList = new ArrayList<Integer>();
+ }
+ if (mOrderList != null) {
+ mOrderList.add(Integer.parseInt(mParser.nextText()));
+ }
+ }
+ }
+ } catch (XmlPullParserException e) {
+ Log.i(TAG, "XmlPullParserException caught in processStartElement()");
+ ret = false;
+ } catch (IOException e) {
+ Log.i(TAG, "IOException caught in processStartElement()");
+ ret = false;
+ } finally {
+ return ret;
+ }
+ }
+
+ void processEndElement(String name) {
+ if (name.equalsIgnoreCase(SENSOR)) {
+ // insert in map, only if no sensor with same name already in map
+ if (mCurrSensor == null) return;
+ mCurrSensor.setAutoValues();
+ if (ThermalManager.getSensor(mCurrSensor.getSensorName()) == null) {
+ ThermalManager.sSensorMap.put(mCurrSensor.getSensorName(), mCurrSensor);
+ } else {
+ Log.i(TAG, "sensor:" + mCurrSensor.getSensorName() + " already present");
+ }
+ mCurrSensor = null;
+ } else if (name.equalsIgnoreCase(SENSOR_ATTRIB) && mCurrSensorAttribList != null) {
+ if (mCurrSensorAttrib != null) {
+ mCurrSensorAttrib.setWeights(mWeightList);
+ mCurrSensorAttrib.setOrder(mOrderList);
+ }
+ mWeightList = null;
+ mOrderList = null;
+ if (mCurrSensorAttrib != null
+ && ThermalManager.getSensor(mCurrSensorAttrib.getSensorName()) != null) {
+ // this is valid sensor, so now update the zone sensorattrib list
+ // and sensor list.This check is needed to avoid a scenario where
+ // a invalid sensor name might be included in sensorattrib list.
+ // This check filters out all invalid sensor attrib.
+ mCurrSensorAttribList.add(mCurrSensorAttrib);
+ }
+ } else if (name.equalsIgnoreCase(ZONE) && mCurrZone != null
+ && mThermalZones != null) {
+ mCurrZone.setSensorList(mCurrSensorAttribList);
+ mThermalZones.add(mCurrZone);
+ mCurrZone = null;
+ mTempZoneId = -1;
+ mTempZoneName = null;
+ mCurrSensorAttribList = null;
+ } else if (name.equalsIgnoreCase(POLLDELAY) && mCurrZone != null) {
+ mCurrZone.setPollDelay(mPollDelayList);
+ mPollDelayList = null;
+ } else if (name.equalsIgnoreCase(MOVINGAVGWINDOW) && mCurrZone != null) {
+ mCurrZone.setMovingAvgWindow(mMovingAvgWindowList);
+ mMovingAvgWindowList = null;
+ } else if (name.equalsIgnoreCase(THERMAL_CONFIG)) {
+ // This indicates we have not seen any <Profile> tag.
+ // Consider it as if we have only one 'Default' Profile.
+ if (mNumProfiles == 0) {
+ ThermalManager.sProfileZoneMap.put(mCurProfileName, mThermalZones);
+ }
+ mDone = true;
+ } else if (name.equalsIgnoreCase(PROFILE)) {
+ ThermalManager.sProfileZoneMap.put(mCurProfileName, mThermalZones);
+ mThermalZones = null;
+ } else if (name.equalsIgnoreCase(ZONETHRESHOLD) && mCurrZone != null) {
+ mCurrZone.setZoneTempThreshold(mZoneThresholdList);
+ mZoneThresholdList = null;
+ }
+ }
+ }
+
+ /* Class to notifying thermal events */
+ public class Notify implements Runnable {
+ private final BlockingQueue cQueue;
+ Notify (BlockingQueue q) {
+ cQueue = q;
+ }
+
+ public void run () {
+ try {
+ while (true) { consume((ThermalEvent) cQueue.take()); }
+ } catch (InterruptedException ex) {
+ Log.i(TAG, "caught InterruptedException in run()");
+ }
+ }
+
+ /* Method to consume thermal event */
+ public void consume (ThermalEvent event) {
+ Intent statusIntent = new Intent();
+ statusIntent.setAction(ThermalManager.ACTION_THERMAL_ZONE_STATE_CHANGED);
+
+ statusIntent.putExtra(ThermalManager.EXTRA_NAME, event.mZoneName);
+ statusIntent.putExtra(ThermalManager.EXTRA_PROFILE, event.mProfName);
+ statusIntent.putExtra(ThermalManager.EXTRA_ZONE, event.mZoneId);
+ statusIntent.putExtra(ThermalManager.EXTRA_EVENT, event.mEventType);
+ statusIntent.putExtra(ThermalManager.EXTRA_STATE, event.mThermalLevel);
+ statusIntent.putExtra(ThermalManager.EXTRA_TEMP, event.mZoneTemp);
+
+ /* Send the Thermal Intent */
+ mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+ }
+ }
+
+ /* Register for boot complete Intent */
+ public ThermalService() {
+ super();
+ }
+
+ private void configureTurboProperties() {
+ String prop = SystemProperties.get("persist.thermal.turbo.dynamic");
+
+ if (prop.equals("0")) {
+ ThermalManager.sIsDynamicTurboEnabled = false;
+ Log.i(TAG, "Dynamic Turbo disabled through persist.thermal.turbo.dynamic");
+ } else if (prop.equals("1")) {
+ ThermalManager.sIsDynamicTurboEnabled = true;
+ Log.i(TAG, "Dynamic Turbo enabled through persist.thermal.turbo.dynamic");
+ } else {
+ // Set it to true so that we don't write ThermalManager.DISABLE_DYNAMIC_TURBO
+ // into any cooling device based on this.
+ ThermalManager.sIsDynamicTurboEnabled = true;
+ Log.i(TAG, "property persist.thermal.turbo.dynamic not present");
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ // stop all thread
+ ThermalManager.stopCurrentProfile();
+ ThermalManager.sCoolingManager.unregisterReceivers();
+ // clear all static data
+ ThermalManager.clearData();
+ Log.w(TAG, "ituxd destroyed");
+ }
+
+ @Override
+ public void onCreate() {
+ mContext = getApplicationContext();
+ ThermalManager.setContext(mContext);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return(null);
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startid)
+ {
+ boolean ret;
+ ThermalManager.loadiTUXVersion();
+ /* Check for exitence of config files */
+ ThermalUtils.initialiseConfigFiles(mContext);
+ if (!ThermalManager.sIsConfigFiles && !ThermalManager.sIsOverlays) {
+ Log.i(TAG, "Thermal config files do not exist. Exiting ThermalService");
+ return START_NOT_STICKY;
+ }
+
+ /* Set Dynamic Turbo status based on the property */
+ configureTurboProperties();
+
+ /* Intiliaze DTS TjMax temperature */
+ ThermalUtils.getTjMax();
+
+ /* Initialize the Thermal Cooling Manager */
+ ThermalManager.sCoolingManager = new ThermalCooling();
+ if (ThermalManager.sCoolingManager != null) {
+ ret = ThermalManager.sCoolingManager.init(mContext);
+ if (!ret) {
+ Log.i(TAG, "CoolingManager is null. Exiting ThermalService");
+ return START_NOT_STICKY;
+ }
+ }
+
+ /* Parse the thermal configuration file to determine zone/sensor information */
+ ThermalParser mThermalParser;
+ if (ThermalManager.sIsConfigFiles) {
+ mThermalParser = new ThermalParser(ThermalManager.sSensorFilePath);
+ } else {
+ mThermalParser = new ThermalParser();
+ }
+
+ if (mThermalParser != null) {
+ ret = mThermalParser.parse();
+ if (!ret) {
+ ThermalManager.sCoolingManager.unregisterReceivers();
+ Log.i(TAG, "thermal_sensor_config.xml parsing Failed. Exiting ThermalService");
+ return START_NOT_STICKY;
+ }
+ }
+
+ /* Retrieve the platform information after parsing */
+ ThermalManager.sPlatformInfo = mThermalParser.getPlatformInfo();
+
+ /* Print thermal_sensor_config.xml information */
+ Iterator it = ThermalManager.sProfileZoneMap.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry entry = (Map.Entry) it.next();
+ String key = (String) entry.getKey();
+ ArrayList<ThermalZone> tzList = (ArrayList<ThermalZone>) entry.getValue();
+ Log.i(TAG, "Zones under Profile: " + key);
+ for (ThermalZone tz : tzList) tz.printAttrs();
+ }
+
+ /* read persistent system properties for shutdown notification */
+ ThermalManager.readShutdownNotiferProperties();
+ /* initialize the thermal notifier thread */
+ Notify notifier = new Notify(ThermalManager.sEventQueue);
+ new Thread(notifier, "ThermalNotifier").start();
+
+ ThermalManager.buildProfileNameList();
+ ThermalManager.initializeStickyIntent();
+
+ /* Building bucket size for all profiles */
+ ThermalManager.setBucketSizeForProfiles();
+
+ /* Start monitoring the zones in Default Thermal Profile */
+ ThermalManager.startDefaultProfile();
+
+ return START_STICKY;
+ }
+}
diff --git a/ituxd/src/com/intel/thermal/ThermalUtils.java b/ituxd/src/com/intel/thermal/ThermalUtils.java
new file mode 100644
index 0000000..7126f9b
--- /dev/null
+++ b/ituxd/src/com/intel/thermal/ThermalUtils.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2014 Intel Corporation All Rights Reserved.
+ *
+ * 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.
+ */
+
+package com.intel.thermal;
+
+import android.content.Context;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.File;
+
+/* importing static variables */
+import static com.intel.thermal.ThermalManager.*;
+
+/**
+ * The ThermalUtils class contains all common utility functionality
+ * implementations
+ *
+ * @hide
+ */
+public class ThermalUtils {
+ private static final String TAG = "ThermalUtils";
+
+ /* Native methods to access Sysfs Interfaces */
+ private native static String native_readSysfs(String path);
+ private native static int native_writeSysfs(String path, int val);
+ private native static int native_getThermalZoneIndex(String name);
+ private native static int native_getThermalZoneIndexContains(String name);
+ private native static int native_getCoolingDeviceIndex(String name);
+ private native static int native_getCoolingDeviceIndexContains(String name);
+ private native static boolean native_isFileExists(String name);
+
+ // native methods to access kernel sysfs layer
+ public static String readSysfs(String path) {
+ try {
+ return native_readSysfs(path);
+ } catch (UnsatisfiedLinkError e) {
+ Log.w(TAG, "caught UnsatisfiedLinkError in readSysfs");
+ return null;
+ }
+ }
+
+ public static int writeSysfs(String path, int val) {
+ try {
+ return native_writeSysfs(path, val);
+ } catch (UnsatisfiedLinkError e) {
+ Log.w(TAG, "caught UnsatisfiedLinkError in writeSysfs");
+ return -1;
+ }
+ }
+
+ public static int getThermalZoneIndex(String name) {
+ try {
+ return native_getThermalZoneIndex(name);
+ } catch (UnsatisfiedLinkError e) {
+ Log.w(TAG, "caught UnsatisfiedLinkError in getThermalZoneIndex");
+ return -1;
+ }
+ }
+
+ public static int getThermalZoneIndexContains(String name) {
+ try {
+ return native_getThermalZoneIndexContains(name);
+ } catch (UnsatisfiedLinkError e) {
+ Log.w(TAG, "caught UnsatisfiedLinkError in getThermalZoneIndexContains");
+ return -1;
+ }
+ }
+
+ public static int getCoolingDeviceIndex(String name) {
+ try {
+ return native_getCoolingDeviceIndex(name);
+ } catch (UnsatisfiedLinkError e) {
+ Log.w(TAG, "caught UnsatisfiedLinkError in getCoolingDeviceIndex");
+ return -1;
+ }
+ }
+
+ public static int getCoolingDeviceIndexContains(String name) {
+ try {
+ return native_getCoolingDeviceIndexContains(name);
+ } catch (UnsatisfiedLinkError e) {
+ Log.w(TAG, "caught UnsatisfiedLinkError in getCoolingDeviceIndexContains");
+ return -1;
+ }
+ }
+
+ public static boolean isFileExists(String path) {
+ try {
+ return native_isFileExists(path);
+ } catch (UnsatisfiedLinkError e) {
+ Log.w(TAG, "caught UnsatisfiedLinkError in isFileExists");
+ return false;
+ }
+ }
+
+
+ public static int calculateThermalState(int temp, Integer thresholds[]) {
+ if (thresholds == null) return THERMAL_STATE_OFF;
+ // Return OFF state if temperature less than starting of thresholds
+ if (temp < thresholds[0])
+ return THERMAL_STATE_OFF;
+
+ if (temp >= thresholds[thresholds.length - 2])
+ return (thresholds.length - 2);
+
+ for (int i = 0; i < thresholds.length - 1; i++) {
+ if (temp >= thresholds[i] && temp < thresholds[i + 1]) {
+ return i;
+ }
+ }
+
+ // should never come here
+ return THERMAL_STATE_OFF;
+ }
+
+ public static int getLowerThresholdTemp(int index, Integer thresholds[]) {
+ if (thresholds == null) return INVALID_TEMP;
+ if (index < 0 || index >= thresholds.length)
+ return INVALID_TEMP;
+ return thresholds[index];
+ }
+
+ public static int getUpperThresholdTemp(int index, Integer thresholds[]) {
+ if (thresholds == null) return INVALID_TEMP;
+ if (index < 0 || index >= thresholds.length)
+ return INVALID_TEMP;
+ return thresholds[index + 1];
+ }
+
+ public static void getTjMax() {
+ String temp_tjmax;
+
+ temp_tjmax = readSysfs(ThermalManager.TJMAX_PATH);
+ if (temp_tjmax != null) {
+ try {
+ ThermalManager.sTjMaxTemp = Integer.parseInt(temp_tjmax);
+ Log.i(TAG, "TjMax temp = " + ThermalManager.sTjMaxTemp);
+ } catch (NumberFormatException e) {
+ ThermalManager.sTjMaxTemp = ThermalManager.sDefaultTjMax;
+ Log.i(TAG, "TjMax value invalid, Default TjMax value =" +
+ ThermalManager.sTjMaxTemp);
+ }
+ } else {
+ ThermalManager.sTjMaxTemp = ThermalManager.sDefaultTjMax;
+ Log.i(TAG, "TjMax temp read failed, Default TjMax value =" +
+ ThermalManager.sTjMaxTemp);
+ }
+ }
+
+ public static void initialiseConfigFiles(Context context) {
+ if ("1".equals(SystemProperties.get("persist.thermal.debug.xml", "0"))) {
+ if (isFileExists(DEBUG_DIR_PATH + SENSOR_FILE_NAME) &&
+ isFileExists(DEBUG_DIR_PATH + THROTTLE_FILE_NAME)) {
+ sSensorFilePath = DEBUG_DIR_PATH + SENSOR_FILE_NAME;
+ sThrottleFilePath = DEBUG_DIR_PATH + THROTTLE_FILE_NAME;
+ Log.i(TAG, "Reading thermal config files from /data/");
+ sIsConfigFiles = true;
+ } else {
+ Log.i(TAG, "systemProperty set to read config files from /data/, but files absent");
+ }
+ } else if (isFileExists(DEFAULT_DIR_PATH + SENSOR_FILE_NAME) &&
+ isFileExists(DEFAULT_DIR_PATH + THROTTLE_FILE_NAME)) {
+ sSensorFilePath = DEFAULT_DIR_PATH + SENSOR_FILE_NAME;
+ sThrottleFilePath = DEFAULT_DIR_PATH + THROTTLE_FILE_NAME;
+ Log.i(TAG, "Reading thermal config files from /system/etc/");
+ sIsConfigFiles = true;
+ } else {
+ sSensorFileXmlId = context.getResources().
+ getIdentifier("thermal_sensor_config", "xml", "com.intel.thermal");
+ sThrottleFileXmlId = context.getResources().
+ getIdentifier("thermal_throttle_config", "xml", "com.intel.thermal");
+ if (sSensorFileXmlId != 0 && sThrottleFileXmlId != 0) {
+ Log.i(TAG, "Reading thermal config files from overlays");
+ sIsOverlays = true;
+ } else {
+ Log.i(TAG, "Unable to retrieve config files from overlays");
+ }
+ }
+ }
+}
diff --git a/ituxd/src/com/intel/thermal/ThermalZone.java b/ituxd/src/com/intel/thermal/ThermalZone.java
new file mode 100644
index 0000000..a3af5af
--- /dev/null
+++ b/ituxd/src/com/intel/thermal/ThermalZone.java
@@ -0,0 +1,633 @@
+/*
+ * Copyright 2014 Intel Corporation All Rights Reserved.
+ *
+ * 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.
+ */
+
+package com.intel.thermal;
+
+import android.os.UEventObserver;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+/**
+ * The ThermalZone class contains attributes of a Thermal zone. A Thermal zone
+ * can have one or more sensors associated with it. Whenever the temperature of a
+ * thermal zone crosses the thresholds configured, actions are taken.
+ */
+public class ThermalZone {
+
+ private static final String TAG = "ThermalZone";
+
+ protected int mZoneID; /* ID of the Thermal zone */
+ protected int mCurrThermalState; /* Current thermal state of the zone */
+ protected int mCurrEventType; /* specifies thermal event type, HIGH or LOW */
+ protected String mZoneName; /* Name of the Thermal zone */
+ protected int mMaxStates;
+ /* List of sensors under this thermal zone */
+ protected ArrayList<ThermalSensor> mThermalSensors = null;
+ // sensor name - sensorAttrib object hash to improve lookup performace
+ // during runtime thermal monitoring like re-programming sensor thresholds
+ // calculating weighted zone temp.
+ protected Hashtable<String, ThermalSensorAttrib> mThermalSensorsAttribMap = null;
+ protected int mZoneTemp; /* Temperature of the Thermal Zone */
+ protected boolean mSupportsEmulTemp = true;
+ private int mDebounceInterval; /* Debounce value to avoid thrashing of throttling actions */
+ private Integer mPollDelay[]; /* Delay between sucessive polls in milli seconds */
+ protected boolean mSupportsUEvent; /* Determines if Sensor supports Uevents */
+ private String mZoneLogic; /* Logic to be used to determine thermal state of zone */
+ private boolean mIsZoneActive = false;
+ private boolean mMaxThreshExceeded = false;
+ private int mTripMax;
+ private int mOffset = 0;
+ protected Integer mZoneTempThresholds[]; /* Array containing temperature thresholds */
+ // mZoneTempThresholdsRaw contains the Raw thresholds (as specified in xml).
+ // mZoneTempThresholds contsins the calibrated thresholds that are used
+ // to detect zone state change at runtime.
+ protected Integer mZoneTempThresholdsRaw[];
+
+ /* MovingAverage related declarations */
+ private int mRecordedValuesHead = -1; /* Index pointing to the head of past values of sensor */
+ private int mRecordedValues[]; /* Recorded values of sensor */
+ private int mNumberOfInstances[]; /* Number of recorded instances to be considered */
+ private ArrayList<Integer> mWindowList = null;
+ private boolean mIsMovingAverage = false; /* By default false */
+
+ // override this method in ModemZone to limit num states to default
+ public void setMaxStates(int state) {
+ mMaxStates = state;
+ }
+
+ public void updateMaxStates(int state) {
+ setMaxStates(state);
+ }
+
+ public int getMaxStates() {
+ return mMaxStates;
+ }
+
+ public boolean getMovingAverageFlag() {
+ return mIsMovingAverage;
+ }
+
+ public void setMovingAvgWindow(ArrayList<Integer> windowList) {
+ int maxValue = Integer.MIN_VALUE; // -2^31
+
+ if (windowList == null || mPollDelay == null) {
+ Log.i(TAG, "setMovingAvgWindow input is null");
+ mIsMovingAverage = false;
+ return;
+ }
+ mNumberOfInstances = new int[windowList.size()];
+ if (mNumberOfInstances == null) {
+ Log.i(TAG, "failed to create poll windowlist");
+ mIsMovingAverage = false;
+ return;
+ }
+ mIsMovingAverage = true;
+ for (int i = 0; i < windowList.size(); i++) {
+ if (mPollDelay[i] == 0) {
+ mIsMovingAverage = false;
+ Log.i(TAG, "Polling delay is zero, WMA disabled\n");
+ return;
+ }
+ mNumberOfInstances[i] = windowList.get(i) / mPollDelay[i];
+ if (mNumberOfInstances[i] <= 0) {
+ mIsMovingAverage = false;
+ Log.i(TAG, "Polling delay greater than moving average window, WMA disabled\n");
+ return;
+ }
+ maxValue = Math.max(mNumberOfInstances[i], maxValue);
+ }
+ mRecordedValues = new int[maxValue];
+ }
+
+ public int movingAverageTemp() {
+ int index, calIndex;
+ int predictedTemp = 0;
+
+ mRecordedValuesHead = (mRecordedValuesHead + 1) % mRecordedValues.length;
+ mRecordedValues[mRecordedValuesHead] = mZoneTemp;
+
+ // Sensor State starts with -1, InstancesList starts with 0
+ for (index = 0; index < mNumberOfInstances[mCurrThermalState + 1]; index++) {
+ calIndex = mRecordedValuesHead - index;
+ if (calIndex < 0) {
+ calIndex = mRecordedValues.length + calIndex;
+ }
+ predictedTemp += mRecordedValues[calIndex];
+ }
+ return predictedTemp / index;
+ }
+
+ public void printAttrs() {
+ Log.i(TAG, "mZoneID:" + Integer.toString(mZoneID));
+ Log.i(TAG, "mDBInterval: " + Integer.toString(mDebounceInterval));
+ Log.i(TAG, "mZoneName:" + mZoneName);
+ Log.i(TAG, "mSupportsUEvent:" + Boolean.toString(mSupportsUEvent));
+ Log.i(TAG, "mZoneLogic:" + mZoneLogic);
+ Log.i(TAG, "mOffset:" + mOffset);
+ Log.i(TAG, "mPollDelay[]:" + Arrays.toString(mPollDelay));
+ Log.i(TAG, "mZoneTempThresholds[]: " + Arrays.toString(mZoneTempThresholds));
+ Log.i(TAG, "mNumberOfInstances[]: " + Arrays.toString(mNumberOfInstances));
+ Log.i(TAG, "mEmulTempFlag:" + mSupportsEmulTemp);
+ Log.i(TAG, "MaxStates:" + getMaxStates());
+ printStateThresholdMap();
+ printSensors();
+ printSensorAttribList();
+ }
+
+ public void printStateThresholdMap() {
+ if (mZoneTempThresholds == null
+ || mZoneTempThresholds.length < ThermalManager.DEFAULT_NUM_ZONE_STATES) return;
+ StringBuilder s = new StringBuilder();
+ s.append("[" + "State0" + "<" + mZoneTempThresholds[1] + "];");
+ for (int index = 2; index < getMaxStates(); index++) {
+ int curstate = index - 1;
+ s.append("[" + mZoneTempThresholds[index - 1] + "<=" + "State"
+ + curstate + "<" + mZoneTempThresholds[index] + "];");
+ }
+ Log.i(TAG, "states-threshold map:" + s.toString());
+ }
+
+ private void printSensors() {
+ if (mThermalSensors == null) return;
+ StringBuilder s = new StringBuilder();
+ for (ThermalSensor ts : mThermalSensors) {
+ if (ts != null) {
+ s.append(ts.getSensorName());
+ s.append(",");
+ }
+ }
+ Log.i(TAG, "zoneID: " + mZoneID + " sensors mapped:" + s.toString());
+ }
+
+ private void printSensorAttribList() {
+ if (mThermalSensorsAttribMap == null) return;
+ Iterator it = (Iterator) mThermalSensorsAttribMap.keySet().iterator();
+ if (it == null) return;
+ ThermalSensorAttrib sensorAttrib = null;
+ while (it.hasNext()) {
+ sensorAttrib = mThermalSensorsAttribMap.get((String) it.next());
+ if (sensorAttrib != null) sensorAttrib.printAttrs();
+ }
+ }
+
+ public ThermalZone() {
+ mCurrThermalState = ThermalManager.THERMAL_STATE_OFF;
+ mZoneTemp = ThermalManager.INVALID_TEMP;
+ }
+
+ public static String getStateAsString(int index) {
+ if (index < -1 || index > 3)
+ return "Invalid";
+ return ThermalManager.STATE_NAMES[index + 1];
+ }
+
+ public static String getEventTypeAsString(int type) {
+ return type == 0 ? "LOW" : "HIGH";
+ }
+
+ public void setSensorList(ArrayList<ThermalSensorAttrib> sensorAtribList) {
+ if (sensorAtribList == null || ThermalManager.sSensorMap == null) return;
+ for (ThermalSensorAttrib sa : sensorAtribList) {
+ // since each object of sensor attrib list is already validated during
+ // parsing it is gauranteed that 'sa != null' and a valid sensor object 's'
+ // will be returned. Hence skipping null check..
+ if (mThermalSensors == null) {
+ // first time allocation
+ mThermalSensors = new ArrayList<ThermalSensor>();
+ if (mThermalSensors == null) {
+ // allocation failure. return
+ return;
+ }
+ }
+ if (mThermalSensorsAttribMap == null) {
+ // first time allocation
+ mThermalSensorsAttribMap = new Hashtable<String, ThermalSensorAttrib>();
+ if (mThermalSensorsAttribMap == null) return;
+ }
+ mThermalSensors.add(ThermalManager.getSensor(sa.getSensorName()));
+ mThermalSensorsAttribMap.put(sa.getSensorName(), sa);
+ }
+ }
+
+ public ArrayList<ThermalSensor> getThermalSensorList() {
+ return mThermalSensors;
+ }
+
+ public int getZoneState() {
+ return mCurrThermalState;
+ }
+
+ public void setZoneState(int state) {
+ mCurrThermalState = state;
+ }
+
+ public int getEventType() {
+ return mCurrEventType;
+ }
+
+ public void setEventType(int type) {
+ mCurrEventType = type;
+ }
+
+ public void setZoneTemp(int temp) {
+ mZoneTemp = temp;
+ }
+
+ public int getZoneTemp() {
+ return mZoneTemp;
+ }
+
+ public void setZoneId(int id) {
+ mZoneID = id;
+ }
+
+ public int getZoneId() {
+ return mZoneID;
+ }
+
+ public void setZoneName(String name) {
+ mZoneName = name;
+ }
+
+ public String getZoneName() {
+ return mZoneName;
+ }
+
+ public void setSupportsUEvent(int flag) {
+ mSupportsUEvent = (flag == 1);
+ }
+
+ public boolean isUEventSupported() {
+ return mSupportsUEvent;
+ }
+
+ public boolean isMaxThreshExceed() {
+ return mMaxThreshExceeded;
+ }
+
+ public void setZoneLogic(String type) {
+ mZoneLogic = type;
+ }
+
+ public String getZoneLogic() {
+ return mZoneLogic;
+ }
+
+ public void setDBInterval(int interval) {
+ mDebounceInterval = interval;
+ }
+
+ public int getDBInterval() {
+ return mDebounceInterval;
+ }
+
+ public int getOffset() {
+ return mOffset;
+ }
+
+ public void setOffset(int offset) {
+ mOffset = offset;
+ }
+
+ public void setPollDelay(ArrayList<Integer> delayList) {
+ if (delayList != null) {
+ mPollDelay = new Integer[delayList.size()];
+ if (mPollDelay != null) {
+ mPollDelay = delayList.toArray(mPollDelay);
+ }
+ }
+ }
+
+ public Integer[] getPollDelay() {
+ return mPollDelay;
+ }
+
+ /**
+ * In polldelay array, index of TOFF = 0, Normal = 1, Warning = 2, Alert =
+ * 3, Critical = 4. Whereas a ThermalZone states are enumerated as TOFF =
+ * -1, Normal = 0, Warning = 1, Alert = 2, Critical = 3. Hence we add 1
+ * while querying poll delay
+ */
+ public int getPollDelay(int index) {
+ index++;
+
+ // If poll delay is requested for an invalid state, return the delay
+ // corresponding to normal state
+ if (index < 0 || index >= mPollDelay.length)
+ index = 1;
+
+ return mPollDelay[index];
+ }
+
+ public void setZoneTempThreshold(ArrayList<Integer> thresholdList) {
+ if (mZoneName.contains("CPU") || mZoneName.contains("SoC"))
+ mTripMax = ThermalManager.sTjMaxTemp;
+ else
+ mTripMax = ThermalManager.sMaxSkinTrip;
+
+ if (thresholdList != null ) {
+ // In Uevent mode, if any threshold specified for a particular
+ // zone exceeds the max threshold temp, we de-activate that zone.
+ if (mSupportsUEvent) {
+ for (int i = 0; i < thresholdList.size(); i++) {
+ if (thresholdList.get(i) <= mTripMax)
+ continue;
+ else
+ mMaxThreshExceeded = true;
+ }
+ }
+ if (mMaxThreshExceeded == false) {
+ mZoneTempThresholds = new Integer[thresholdList.size()];
+ mZoneTempThresholdsRaw = new Integer[thresholdList.size()];
+ if (mZoneTempThresholds != null) {
+ mZoneTempThresholds = thresholdList.toArray(mZoneTempThresholds);
+ }
+ if (mZoneTempThresholdsRaw != null) {
+ mZoneTempThresholdsRaw = thresholdList.toArray(mZoneTempThresholdsRaw);
+ }
+ }
+ }
+ }
+
+ public int getZoneTempThreshold(int index) {
+ if (index < 0 || index >= mZoneTempThresholds.length)
+ return -1;
+ return mZoneTempThresholds[index];
+ }
+
+ public Integer[] getZoneTempThreshold() {
+ return mZoneTempThresholds;
+ }
+
+ public boolean getZoneActiveStatus() {
+ return mIsZoneActive;
+ }
+
+ public void computeZoneActiveStatus() {
+ // init again. needed because of a profile change
+ mIsZoneActive = false;
+ if (mSupportsUEvent) {
+ // Zone de-activated when any threshold for that zone is
+ // above the allowed Max threshold.
+ if (mMaxThreshExceeded == true) {
+ Log.i(TAG, "deactivate zone:" + mZoneName +
+ ". Zone Threshold exceeds max trip temp:" + mTripMax);
+ mIsZoneActive = false;
+ return;
+ }
+ }
+ if (mZoneTempThresholds == null) {
+ Log.i(TAG, "deactivate zone:" + getZoneName() + " threshold list is NULL! ");
+ mIsZoneActive = false;
+ return;
+ }
+ // 1. minimum number of states supported must be DEFAULT NUM STATES
+ // 2. if sensor list null disable zone
+ if (mMaxStates < ThermalManager.DEFAULT_NUM_ZONE_STATES) {
+ // substract by 1 since TOFF is transparent to USER
+ int minStateSupport = ThermalManager.DEFAULT_NUM_ZONE_STATES - 1;
+ Log.i(TAG, "deactivate zone:" + getZoneName() + " supports < "
+ + minStateSupport + " states");
+ mIsZoneActive = false;
+ return;
+ }
+ if (mThermalSensors == null) {
+ Log.i(TAG, "deactivate zone:" + getZoneName() + " sensor list null! ");
+ mIsZoneActive = false;
+ return;
+ }
+
+ if (mSupportsUEvent) {
+ // if uevent just check the first sensor
+ ThermalSensor s = mThermalSensors.get(0);
+ if (s != null && s.getSensorActiveStatus()) {
+ mIsZoneActive = true;
+ return;
+ }
+ } else {
+ if (mPollDelay == null) {
+ Log.i(TAG, "deactivate zone:" + getZoneName()
+ + " polldelay list null in poll mode! ");
+ mIsZoneActive = false;
+ return;
+ }
+ if (mZoneTempThresholds.length != mPollDelay.length) {
+ Log.i(TAG, "deactivate zone:" + getZoneName()
+ + " mismatch of polldelay and threshold list in polling mode!");
+ mIsZoneActive = false;
+ return;
+ }
+ for (ThermalSensor ts : mThermalSensors) {
+ if (ts != null && ts.getSensorActiveStatus()) {
+ mIsZoneActive = true;
+ return;
+ }
+ }
+ }
+ }
+
+ public void setEmulTempFlag(int flag) {
+ mSupportsEmulTemp = (flag == 1);
+ }
+
+ public boolean getEmulTempFlag() {
+ return mSupportsEmulTemp;
+ }
+
+ // override in Specific zone class which inherit ThermalZone
+ public void startMonitoring() {
+ }
+
+ // override in Specific zone class which inherit ThermalZone
+ public void stopMonitoring() {
+ }
+
+ // override in ModemZone to unregister Modem specific intents
+ // override in VirtualThermalZone to stop UEvent observers
+ public void unregisterReceiver() {
+ if (isUEventSupported()) {
+ mUEventObserver.stopObserving();
+ }
+ }
+
+ // override in VirtualThermalZone class
+ public void startEmulTempObserver() {
+ }
+
+ // override in VirtualThermalZone class
+ public void calibrateThresholds() {
+ }
+
+ /**
+ * Function that calculates the state of the Thermal Zone after reading
+ * temperatures of all sensors in the zone. This function is used when a
+ * zone operates in polling mode.
+ */
+ public boolean isZoneStateChanged() {
+ for (ThermalSensor ts : mThermalSensors) {
+ if (ts.getSensorActiveStatus()) {
+ ts.updateSensorTemp();
+ }
+ }
+ return updateZoneParams();
+ }
+
+ /**
+ * Function that calculates the state of the Thermal Zone after reading
+ * temperatures of all sensors in the zone. This is an overloaded function
+ * used when a zone supports UEvent notifications from kernel. When a
+ * sensor sends an UEvent, it also sends its current temperature as a
+ * parameter of the UEvent.
+ */
+ public boolean isZoneStateChanged(ThermalSensor s, int temp) {
+ if (s == null) return false;
+ s.setCurrTemp(temp);
+ setZoneTemp(temp);
+ return updateZoneParams();
+ }
+
+ /**
+ * Method to update Zone Temperature and Zone Thermal State
+ */
+ public boolean updateZoneParams() {
+ int newZoneState;
+ int prevZoneState = mCurrThermalState;
+
+ if (!updateZoneTemp()) {
+ return false;
+ }
+
+ newZoneState = ThermalUtils.calculateThermalState(mZoneTemp, mZoneTempThresholds);
+ if (newZoneState == prevZoneState) {
+ return false;
+ }
+
+ if (newZoneState == ThermalManager.THERMAL_STATE_OFF) {
+ setZoneState(newZoneState);
+ return true;
+ }
+
+ int threshold = ThermalUtils.getLowerThresholdTemp(prevZoneState, mZoneTempThresholds);
+ // For Interrupt based zones, HW (should) takes care of the debounce.
+ if (!isUEventSupported()) {
+ if (newZoneState < prevZoneState && getZoneTemp() > (threshold - getDBInterval())) {
+ Log.i(TAG, " THERMAL_LOW_EVENT for zone:" + getZoneName()
+ + " rejected due to debounce interval");
+ return false;
+ }
+ }
+
+ setZoneState(newZoneState);
+ setEventType(newZoneState > prevZoneState
+ ? ThermalManager.THERMAL_HIGH_EVENT
+ : ThermalManager.THERMAL_LOW_EVENT);
+ return true;
+ }
+
+ public boolean updateZoneTemp() {
+ return false;
+ }
+
+ public void registerUevent() {
+ int indx;
+
+ if (mThermalSensors == null) return;
+ if (mThermalSensors.size() > 1) {
+ Log.i(TAG, "for zone:" + getZoneName() + " in uevent mode only first sensor used!");
+ }
+ ThermalSensor sensor = mThermalSensors.get(0);
+ if (sensor == null) return;
+ String path = sensor.getUEventDevPath();
+ if (path.equalsIgnoreCase("invalid")) return;
+ // first time update of sensor temp and zone temp
+ sensor.updateSensorTemp();
+ setZoneTemp(sensor.getCurrTemp());
+ if (updateZoneParams()) {
+ // first intent after initialization
+ sendThermalEvent();
+ }
+ mUEventObserver.startObserving(path);
+ programThresholds(sensor);
+ }
+
+ public UEventObserver mUEventObserver = new UEventObserver() {
+ @Override
+ public void onUEvent(UEventObserver.UEvent event) {
+ String sensorName;
+ int sensorTemp, errorVal, eventType = -1;
+ ThermalZone zone;
+ if (mThermalSensors == null) return;
+
+ // Name of the sensor and current temperature are mandatory parameters of an UEvent
+ sensorName = event.get("NAME");
+ sensorTemp = Integer.parseInt(event.get("TEMP"));
+
+ // eventType is an optional parameter. so, check for null case
+ if (event.get("EVENT") != null)
+ eventType = Integer.parseInt(event.get("EVENT"));
+
+ if (sensorName != null) {
+ Log.i(TAG, "UEvent received for sensor:" + sensorName + " temp:" + sensorTemp);
+ // check the name against the first sensor
+ ThermalSensor sensor = mThermalSensors.get(0);
+ if (sensor != null && sensor.getSensorName() != null
+ && sensor.getSensorName().equalsIgnoreCase(sensorName)) {
+ // Adjust the sensor temperature based on the 'error correction' temperature.
+ // For 'LOW' event, debounce interval will take care of this.
+ errorVal = sensor.getErrorCorrectionTemp();
+ if (eventType == ThermalManager.THERMAL_HIGH_EVENT)
+ sensorTemp += errorVal;
+
+ if (isZoneStateChanged(sensor, sensorTemp)) {
+ sendThermalEvent();
+ // reprogram threshold
+ programThresholds(sensor);
+ }
+ }
+ }
+ }
+ };
+
+ public void programThresholds(ThermalSensor s) {
+ if (s == null) return;
+ int zoneState = getZoneState();
+ if (zoneState == ThermalManager.THERMAL_STATE_OFF) return;
+ int lowerTripPoint = ThermalUtils.getLowerThresholdTemp(zoneState, getZoneTempThreshold());
+ int upperTripPoint = ThermalUtils.getUpperThresholdTemp(zoneState, getZoneTempThreshold());
+ if (lowerTripPoint != ThermalManager.INVALID_TEMP
+ && upperTripPoint != ThermalManager.INVALID_TEMP) {
+ if (ThermalUtils.writeSysfs(s.getSensorLowTempPath(), lowerTripPoint) == -1) {
+ Log.i(TAG, "error while programming lower trip point:" + lowerTripPoint
+ + "for sensor:" + s.getSensorName());
+ }
+ if (ThermalUtils.writeSysfs(s.getSensorHighTempPath(), upperTripPoint) == -1) {
+ Log.i(TAG, "error while programming upper trip point:" + upperTripPoint
+ + "for sensor:" + s.getSensorName());
+ }
+ }
+ }
+
+ public void sendThermalEvent() {
+ ThermalEvent event = new ThermalEvent(mZoneID, mCurrEventType,
+ mCurrThermalState, mZoneTemp, mZoneName,
+ ThermalManager.getCurProfileName());
+ ThermalManager.addThermalEvent(event);
+ }
+}
diff --git a/ituxd/src/com/intel/thermal/ThermalZoneMonitor.java b/ituxd/src/com/intel/thermal/ThermalZoneMonitor.java
new file mode 100644
index 0000000..5c38b43
--- /dev/null
+++ b/ituxd/src/com/intel/thermal/ThermalZoneMonitor.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2014 Intel Corporation All Rights Reserved.
+ *
+ * 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.
+ */
+
+package com.intel.thermal;
+
+import android.util.Log;
+
+/**
+ * The ThermalZoneMonitor class runs a thread for each zone
+ * with which it is instantiated.
+ *
+ * @hide
+ */
+public class ThermalZoneMonitor implements Runnable {
+ private static final String TAG = "ThermalZoneMonitor";
+ private Thread t;
+ private ThermalZone zone;
+ private String mThreadName;
+ private boolean stop = false;
+
+ public ThermalZoneMonitor(ThermalZone tz) {
+ zone = tz;
+ mThreadName = "ThermalZone" + zone.getZoneId();
+ t = new Thread(this, mThreadName);
+ t.start();
+ }
+
+ public void stopMonitor() {
+ stop = true;
+ t.interrupt();
+ }
+
+ public void run() {
+ try {
+ while (!stop && !t.isInterrupted()) {
+ if (zone.isZoneStateChanged()) {
+ zone.sendThermalEvent();
+ }
+ // stop value can be changed before going to sleep
+ if (!stop) {
+ Thread.sleep(zone.getPollDelay(zone.getZoneState()));
+ }
+ }
+ } catch (InterruptedException iex) {
+ Log.i(TAG, "Stopping thread " + mThreadName + " [InterruptedException]");
+ }
+ }
+}
diff --git a/ituxd/src/com/intel/thermal/VirtualThermalZone.java b/ituxd/src/com/intel/thermal/VirtualThermalZone.java
new file mode 100644
index 0000000..1f4fd4d
--- /dev/null
+++ b/ituxd/src/com/intel/thermal/VirtualThermalZone.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2014 Intel Corporation All Rights Reserved.
+ *
+ * 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.
+ */
+
+package com.intel.thermal;
+
+import android.os.UEventObserver;
+import android.util.Log;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * The VirtualThermalZone class extends the ThermalZone class, with a default
+ * implementation of the isZoneStateChanged() method. This computes the
+ * zone state by computing the equation, which can be linear / higher order implementation
+ * @hide
+ */
+public class VirtualThermalZone extends ThermalZone {
+
+ private static final String TAG = "VirtualThermalZone";
+ private String mEmulTempPath;
+ private ThermalZoneMonitor mTzm = null;
+
+ public void setEmulTempPath(String path) {
+ mEmulTempPath = path;
+ }
+
+ public String getEmulTempPath() {
+ return mEmulTempPath;
+ }
+
+ public VirtualThermalZone() {
+ super();
+ }
+
+ // overridden to start UEvent observer only for Virtual zone
+ public void startEmulTempObserver() {
+ if (!getEmulTempFlag()) {
+ return;
+ }
+ int indx = ThermalUtils.getThermalZoneIndex(getZoneName());
+ if (indx == -1) {
+ Log.i(TAG, "Could not obtain emul_temp sysfs node for " + getZoneName());
+ return;
+ }
+ String uEventDevPath = ThermalManager.sUEventDevPath + indx;
+ setEmulTempPath(ThermalManager.sSysfsSensorBasePath + indx + "/emul_temp");
+ mEmulTempObserver.startObserving(uEventDevPath);
+ }
+
+ public void unregisterReceiver() {
+ super.unregisterReceiver();
+ if (getEmulTempFlag()) {
+ mEmulTempObserver.stopObserving();
+ }
+ }
+
+ public void startMonitoring() {
+ mTzm = new ThermalZoneMonitor(this);
+ }
+
+ public void stopMonitoring() {
+ if (mTzm != null) {
+ mTzm.stopMonitor();
+ }
+ }
+
+ // override fucntion
+ public void calibrateThresholds() {
+ ThermalSensor ts = getThermalSensorList().get(0);
+ ThermalSensorAttrib sa = mThermalSensorsAttribMap.get(ts.getSensorName());
+ if (sa == null) {
+ return;
+ }
+ Integer weights[] = sa.getWeights();
+ int m = weights[0];
+ int c = getOffset();
+
+ if (m == 0) return;
+ for (int i = 0; i < mZoneTempThresholdsRaw.length; i++) {
+ // We do not want to convert '0'. Let it represent 0 C.
+ if (mZoneTempThresholdsRaw[i] == 0) continue;
+ // Get raw systherm temperature: y=mx+c <--> x=(y-c)/m
+ mZoneTempThresholds[i] = ((mZoneTempThresholdsRaw[i] - c) * 1000) / m;
+ }
+ Log.i(TAG, "calibrateThresholds[]: " + Arrays.toString(mZoneTempThresholds));
+ }
+
+ private int calculateZoneTemp() {
+ int curZoneTemp = 0;
+ int weightedTemp;
+ ArrayList<ThermalSensor> list = getThermalSensorList();
+
+ // Check if the SensorList is sane and usable
+ if (list == null || list.get(0) == null) {
+ return ThermalManager.INVALID_TEMP;
+ }
+
+ if (isUEventSupported()) {
+ // for uevent based monitoring only first sensor used
+ ThermalSensor ts = list.get(0);
+ weightedTemp = getWeightedTemp(ts, ts.readSensorTemp());
+ return weightedTemp == ThermalManager.INVALID_TEMP
+ ? ThermalManager.INVALID_TEMP : weightedTemp + getOffset();
+ }
+
+ // Polling mode
+ for (ThermalSensor ts : list) {
+ if (ts != null && ts.getSensorActiveStatus()) {
+ weightedTemp = getWeightedTemp(ts, ts.readSensorTemp());
+ if (weightedTemp == ThermalManager.INVALID_TEMP) {
+ return ThermalManager.INVALID_TEMP;
+ }
+ curZoneTemp += weightedTemp;
+ }
+ }
+ return curZoneTemp + getOffset();
+ }
+
+ private UEventObserver mEmulTempObserver = new UEventObserver() {
+ @Override
+ public void onUEvent(UEventObserver.UEvent event) {
+ String type = event.get("EVENT");
+ if (type == null || Integer.parseInt(type) != ThermalManager.THERMAL_EMUL_TEMP_EVENT) {
+ Log.i(TAG, "EventType does not match");
+ return;
+ }
+
+ if (!getZoneName().equals(event.get("NAME"))) {
+ Log.i(TAG, "ZoneName does not match");
+ return;
+ }
+
+ int temp = calculateZoneTemp();
+ if (temp == ThermalManager.INVALID_TEMP) {
+ Log.i(TAG, "Obtained INVALID_TEMP[0xDEADBEEF]");
+ return;
+ }
+
+ String path = getEmulTempPath();
+ if (path == null) {
+ Log.i(TAG, "EmulTempPath is null");
+ return;
+ }
+
+ int ret = ThermalUtils.writeSysfs(path, temp);
+ if (ret == -1) {
+ Log.i(TAG, "Writing into emul_temp sysfs failed");
+ }
+ }
+ };
+
+ // override function
+ public boolean updateZoneTemp() {
+ int curZoneTemp = ThermalManager.INVALID_TEMP;
+ int rawSensorTemp, sensorTemp;
+ int weightedTemp;
+ boolean flag = false;
+
+ if (isUEventSupported()) {
+ // In UEvent mode, the obtained temperature is the zone temperature
+ return true;
+ } else {
+ for (ThermalSensor ts : getThermalSensorList()) {
+ if (ts != null && ts.getSensorActiveStatus()) {
+ if (flag == false) {
+ // one time initialization of zone temp
+ curZoneTemp = 0;
+ flag = true;
+ }
+ weightedTemp = getWeightedTemp(ts);
+ if (weightedTemp != ThermalManager.INVALID_TEMP) {
+ curZoneTemp += weightedTemp;
+ }
+ }
+ }
+ }
+
+ if (curZoneTemp != ThermalManager.INVALID_TEMP) {
+ curZoneTemp += getOffset();
+ setZoneTemp(curZoneTemp);
+ if (getMovingAverageFlag() && !isUEventSupported()) {
+ // only for polling mode apply moving average on predicted zone temp
+ setZoneTemp(movingAverageTemp());
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ private int getWeightedTemp(ThermalSensor ts) {
+ return getWeightedTemp(ts, ts.getCurrTemp());
+ }
+
+ private int getWeightedTemp(ThermalSensor ts, int rawSensorTemp) {
+ int curZoneTemp = 0;
+ Integer weights[], order[];
+ ThermalSensorAttrib sa = mThermalSensorsAttribMap.get(ts.getSensorName());
+
+ // No point in calculating 'WeightedTemp' on an 'anyway invalid' temperature
+ if (rawSensorTemp == ThermalManager.INVALID_TEMP || sa == null) {
+ return ThermalManager.INVALID_TEMP;
+ }
+
+ weights = sa.getWeights();
+ order = sa.getOrder();
+ if (weights == null && order == null) return rawSensorTemp;
+ if (weights != null) {
+ if (order == null) {
+ // only first weight will be considered
+ return (weights[0] * rawSensorTemp) / 1000;
+ } else if (order != null && weights.length == order.length) {
+ // if order array is provided in xml,
+ // it should be of same size as weights array
+ int sensorTemp = 0;
+ for (int i = 0; i < weights.length; i++) {
+ // Divide by 1000 to convert to mC
+ sensorTemp += (weights[i] * (int) Math.pow(rawSensorTemp, order[i])) / 1000;
+ }
+ return sensorTemp;
+ }
+ }
+ // for every other mismatch return the raw sensor temp
+ return rawSensorTemp;
+ }
+}
diff --git a/ituxd/src/com/intel/thermal/ituxdApp.java b/ituxd/src/com/intel/thermal/ituxdApp.java
new file mode 100644
index 0000000..aa2777d
--- /dev/null
+++ b/ituxd/src/com/intel/thermal/ituxdApp.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.intel.thermal;
+
+import android.app.Application;
+import android.content.Intent;
+import android.os.SystemProperties;
+import android.util.Log;
+
+public class ituxdApp extends Application {
+
+ static final String TAG = "ituxdApp";
+
+ public ituxdApp() {
+
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ if ("1".equals(SystemProperties.get("persist.service.thermal", "0"))) {
+ Log.i(TAG, "Thermal Service enabled");
+ startService(new Intent(this, ThermalService.class));
+ } else {
+ Log.i(TAG, "Thermal Service disabled");
+ }
+ }
+}