Home | History | Annotate | Download | only in thermal
      1 /*
      2  * Copyright 2014 Intel Corporation All Rights Reserved.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.intel.thermal;
     18 
     19 import android.os.UEventObserver;
     20 import android.util.Log;
     21 
     22 import java.util.ArrayList;
     23 import java.util.Arrays;
     24 import java.util.Hashtable;
     25 import java.util.Iterator;
     26 
     27 /**
     28  * The ThermalZone class contains attributes of a Thermal zone. A Thermal zone
     29  * can have one or more sensors associated with it. Whenever the temperature of a
     30  * thermal zone crosses the thresholds configured, actions are taken.
     31  */
     32 public class ThermalZone {
     33 
     34     private static final String TAG = "ThermalZone";
     35 
     36     protected int mZoneID;               /* ID of the Thermal zone */
     37     protected int mCurrThermalState;     /* Current thermal state of the zone */
     38     protected int mCurrEventType;        /* specifies thermal event type, HIGH or LOW */
     39     protected String mZoneName;          /* Name of the Thermal zone */
     40     protected int mMaxStates;
     41     /* List of sensors under this thermal zone */
     42     protected ArrayList<ThermalSensor> mThermalSensors = null;
     43     // sensor name - sensorAttrib object hash to improve lookup performace
     44     // during runtime thermal monitoring like re-programming sensor thresholds
     45     // calculating weighted zone temp.
     46     protected Hashtable<String, ThermalSensorAttrib> mThermalSensorsAttribMap = null;
     47     protected int mZoneTemp;             /* Temperature of the Thermal Zone */
     48     protected boolean mSupportsEmulTemp = true;
     49     private int mDebounceInterval;    /* Debounce value to avoid thrashing of throttling actions */
     50     private Integer mPollDelay[];     /* Delay between sucessive polls in milli seconds */
     51     protected boolean mSupportsUEvent;  /* Determines if Sensor supports Uevents */
     52     private String mZoneLogic;      /* Logic to be used to determine thermal state of zone */
     53     private boolean mIsZoneActive = false;
     54     private boolean mMaxThreshExceeded = false;
     55     private int mTripMax;
     56     private int mOffset = 0;
     57     protected Integer mZoneTempThresholds[];  /* Array containing temperature thresholds */
     58     // mZoneTempThresholdsRaw contains the Raw thresholds (as specified in xml).
     59     // mZoneTempThresholds contsins the calibrated thresholds that are used
     60     // to detect zone state change at runtime.
     61     protected Integer mZoneTempThresholdsRaw[];
     62 
     63     /* MovingAverage related declarations */
     64     private int mRecordedValuesHead = -1; /* Index pointing to the head of past values of sensor */
     65     private int mRecordedValues[];        /* Recorded values of sensor */
     66     private int mNumberOfInstances[];     /* Number of recorded instances to be considered */
     67     private ArrayList<Integer> mWindowList = null;
     68     private boolean mIsMovingAverage = false; /* By default false */
     69 
     70     // override this method in ModemZone to limit num states to default
     71     public void setMaxStates(int state) {
     72         mMaxStates = state;
     73     }
     74 
     75     public void updateMaxStates(int state) {
     76         setMaxStates(state);
     77     }
     78 
     79     public int getMaxStates() {
     80         return mMaxStates;
     81     }
     82 
     83     public boolean getMovingAverageFlag() {
     84         return mIsMovingAverage;
     85     }
     86 
     87     public void setMovingAvgWindow(ArrayList<Integer> windowList) {
     88         int maxValue = Integer.MIN_VALUE; // -2^31
     89 
     90         if (windowList == null || mPollDelay == null) {
     91             Log.i(TAG, "setMovingAvgWindow input is null");
     92             mIsMovingAverage = false;
     93             return;
     94         }
     95         mNumberOfInstances = new int[windowList.size()];
     96         if (mNumberOfInstances == null) {
     97             Log.i(TAG, "failed to create poll windowlist");
     98             mIsMovingAverage = false;
     99             return;
    100         }
    101         mIsMovingAverage = true;
    102         for (int i = 0; i < windowList.size(); i++) {
    103             if (mPollDelay[i] == 0) {
    104                 mIsMovingAverage = false;
    105                 Log.i(TAG, "Polling delay is zero, WMA disabled\n");
    106                 return;
    107             }
    108             mNumberOfInstances[i] = windowList.get(i) / mPollDelay[i];
    109             if (mNumberOfInstances[i] <= 0) {
    110                 mIsMovingAverage = false;
    111                 Log.i(TAG, "Polling delay greater than moving average window, WMA disabled\n");
    112                 return;
    113             }
    114             maxValue = Math.max(mNumberOfInstances[i], maxValue);
    115         }
    116         mRecordedValues = new int[maxValue];
    117     }
    118 
    119     public int movingAverageTemp() {
    120         int index, calIndex;
    121         int predictedTemp = 0;
    122 
    123         mRecordedValuesHead = (mRecordedValuesHead + 1) % mRecordedValues.length;
    124         mRecordedValues[mRecordedValuesHead] = mZoneTemp;
    125 
    126         // Sensor State starts with -1, InstancesList starts with 0
    127         for (index = 0; index < mNumberOfInstances[mCurrThermalState + 1]; index++) {
    128             calIndex = mRecordedValuesHead - index;
    129             if (calIndex < 0) {
    130                 calIndex = mRecordedValues.length + calIndex;
    131             }
    132             predictedTemp += mRecordedValues[calIndex];
    133         }
    134         return predictedTemp / index;
    135     }
    136 
    137     public void printAttrs() {
    138         Log.i(TAG, "mZoneID:" + Integer.toString(mZoneID));
    139         Log.i(TAG, "mDBInterval: " + Integer.toString(mDebounceInterval));
    140         Log.i(TAG, "mZoneName:" + mZoneName);
    141         Log.i(TAG, "mSupportsUEvent:" + Boolean.toString(mSupportsUEvent));
    142         Log.i(TAG, "mZoneLogic:" + mZoneLogic);
    143         Log.i(TAG, "mOffset:" + mOffset);
    144         Log.i(TAG, "mPollDelay[]:" + Arrays.toString(mPollDelay));
    145         Log.i(TAG, "mZoneTempThresholds[]: " + Arrays.toString(mZoneTempThresholds));
    146         Log.i(TAG, "mNumberOfInstances[]: " + Arrays.toString(mNumberOfInstances));
    147         Log.i(TAG, "mEmulTempFlag:" + mSupportsEmulTemp);
    148         Log.i(TAG, "MaxStates:" + getMaxStates());
    149         printStateThresholdMap();
    150         printSensors();
    151         printSensorAttribList();
    152     }
    153 
    154     public void printStateThresholdMap() {
    155         if (mZoneTempThresholds == null
    156                 || mZoneTempThresholds.length < ThermalManager.DEFAULT_NUM_ZONE_STATES) return;
    157         StringBuilder s = new StringBuilder();
    158         s.append("[" + "State0" + "<" + mZoneTempThresholds[1] + "];");
    159         for (int index = 2; index < getMaxStates(); index++) {
    160             int curstate = index - 1;
    161             s.append("[" + mZoneTempThresholds[index - 1] + "<=" + "State"
    162                     + curstate + "<" + mZoneTempThresholds[index] + "];");
    163         }
    164         Log.i(TAG, "states-threshold map:" + s.toString());
    165     }
    166 
    167     private void printSensors() {
    168         if (mThermalSensors == null) return;
    169         StringBuilder s =  new StringBuilder();
    170         for (ThermalSensor ts : mThermalSensors) {
    171             if (ts != null) {
    172                 s.append(ts.getSensorName());
    173                 s.append(",");
    174             }
    175         }
    176         Log.i(TAG, "zoneID: " + mZoneID + " sensors mapped:" + s.toString());
    177     }
    178 
    179     private void printSensorAttribList() {
    180         if (mThermalSensorsAttribMap == null) return;
    181         Iterator it = (Iterator) mThermalSensorsAttribMap.keySet().iterator();
    182         if (it == null) return;
    183         ThermalSensorAttrib sensorAttrib = null;
    184         while (it.hasNext()) {
    185             sensorAttrib = mThermalSensorsAttribMap.get((String) it.next());
    186             if (sensorAttrib != null) sensorAttrib.printAttrs();
    187         }
    188     }
    189 
    190     public ThermalZone() {
    191         mCurrThermalState = ThermalManager.THERMAL_STATE_OFF;
    192         mZoneTemp = ThermalManager.INVALID_TEMP;
    193     }
    194 
    195     public static String getStateAsString(int index) {
    196         if (index < -1 || index > 3)
    197             return "Invalid";
    198         return ThermalManager.STATE_NAMES[index + 1];
    199     }
    200 
    201     public static String getEventTypeAsString(int type) {
    202         return type == 0 ? "LOW" : "HIGH";
    203     }
    204 
    205     public void setSensorList(ArrayList<ThermalSensorAttrib> sensorAtribList) {
    206         if (sensorAtribList == null || ThermalManager.sSensorMap == null) return;
    207         for (ThermalSensorAttrib sa : sensorAtribList) {
    208             // since each object of sensor attrib list is already validated during
    209             // parsing it is gauranteed that 'sa != null' and a valid sensor object 's'
    210             // will be returned. Hence skipping null check..
    211             if (mThermalSensors == null) {
    212                 // first time allocation
    213                 mThermalSensors = new ArrayList<ThermalSensor>();
    214                 if (mThermalSensors == null) {
    215                     // allocation failure. return
    216                     return;
    217                 }
    218             }
    219             if (mThermalSensorsAttribMap == null) {
    220                 // first time allocation
    221                 mThermalSensorsAttribMap = new Hashtable<String, ThermalSensorAttrib>();
    222                 if (mThermalSensorsAttribMap == null) return;
    223             }
    224             mThermalSensors.add(ThermalManager.getSensor(sa.getSensorName()));
    225             mThermalSensorsAttribMap.put(sa.getSensorName(), sa);
    226         }
    227     }
    228 
    229     public ArrayList<ThermalSensor> getThermalSensorList() {
    230         return mThermalSensors;
    231     }
    232 
    233     public int getZoneState() {
    234         return mCurrThermalState;
    235     }
    236 
    237     public void setZoneState(int state) {
    238         mCurrThermalState = state;
    239     }
    240 
    241     public int getEventType() {
    242         return mCurrEventType;
    243     }
    244 
    245     public void setEventType(int type) {
    246         mCurrEventType = type;
    247     }
    248 
    249     public void setZoneTemp(int temp) {
    250         mZoneTemp = temp;
    251     }
    252 
    253     public int getZoneTemp() {
    254         return mZoneTemp;
    255     }
    256 
    257     public void setZoneId(int id) {
    258         mZoneID = id;
    259     }
    260 
    261     public int getZoneId() {
    262         return mZoneID;
    263     }
    264 
    265     public void setZoneName(String name) {
    266         mZoneName = name;
    267     }
    268 
    269     public String getZoneName() {
    270         return mZoneName;
    271     }
    272 
    273     public void setSupportsUEvent(int flag) {
    274         mSupportsUEvent = (flag == 1);
    275     }
    276 
    277     public boolean isUEventSupported() {
    278         return mSupportsUEvent;
    279     }
    280 
    281     public boolean isMaxThreshExceed() {
    282         return mMaxThreshExceeded;
    283     }
    284 
    285     public void setZoneLogic(String type) {
    286         mZoneLogic = type;
    287     }
    288 
    289     public String getZoneLogic() {
    290         return mZoneLogic;
    291     }
    292 
    293     public void setDBInterval(int interval) {
    294         mDebounceInterval = interval;
    295     }
    296 
    297     public int getDBInterval() {
    298         return mDebounceInterval;
    299     }
    300 
    301     public int getOffset() {
    302         return mOffset;
    303     }
    304 
    305     public void setOffset(int offset) {
    306         mOffset  = offset;
    307     }
    308 
    309     public void setPollDelay(ArrayList<Integer> delayList) {
    310         if (delayList != null) {
    311             mPollDelay = new Integer[delayList.size()];
    312             if (mPollDelay != null) {
    313                 mPollDelay = delayList.toArray(mPollDelay);
    314             }
    315         }
    316     }
    317 
    318     public Integer[] getPollDelay() {
    319         return mPollDelay;
    320     }
    321 
    322     /**
    323      * In polldelay array, index of TOFF = 0, Normal = 1, Warning = 2, Alert =
    324      * 3, Critical = 4. Whereas a ThermalZone states are enumerated as TOFF =
    325      * -1, Normal = 0, Warning = 1, Alert = 2, Critical = 3. Hence we add 1
    326      * while querying poll delay
    327      */
    328     public int getPollDelay(int index) {
    329         index++;
    330 
    331         // If poll delay is requested for an invalid state, return the delay
    332         // corresponding to normal state
    333         if (index < 0 || index >= mPollDelay.length)
    334             index = 1;
    335 
    336         return mPollDelay[index];
    337     }
    338 
    339     public void setZoneTempThreshold(ArrayList<Integer> thresholdList) {
    340         if (mZoneName.contains("CPU") || mZoneName.contains("SoC"))
    341             mTripMax = ThermalManager.sTjMaxTemp;
    342         else
    343             mTripMax = ThermalManager.sMaxSkinTrip;
    344 
    345         if (thresholdList != null ) {
    346             // In Uevent mode, if any threshold specified for a particular
    347             // zone exceeds the max threshold temp, we de-activate that zone.
    348             if (mSupportsUEvent) {
    349                 for (int i = 0; i < thresholdList.size(); i++) {
    350                     if (thresholdList.get(i) <= mTripMax)
    351                         continue;
    352                     else
    353                         mMaxThreshExceeded = true;
    354                 }
    355             }
    356             if (mMaxThreshExceeded == false) {
    357                 mZoneTempThresholds = new Integer[thresholdList.size()];
    358                 mZoneTempThresholdsRaw = new Integer[thresholdList.size()];
    359                 if (mZoneTempThresholds != null) {
    360                     mZoneTempThresholds = thresholdList.toArray(mZoneTempThresholds);
    361                 }
    362                 if (mZoneTempThresholdsRaw != null) {
    363                     mZoneTempThresholdsRaw = thresholdList.toArray(mZoneTempThresholdsRaw);
    364                 }
    365             }
    366         }
    367     }
    368 
    369     public int getZoneTempThreshold(int index) {
    370         if (index < 0 || index >= mZoneTempThresholds.length)
    371             return -1;
    372         return mZoneTempThresholds[index];
    373     }
    374 
    375     public Integer[] getZoneTempThreshold() {
    376         return mZoneTempThresholds;
    377     }
    378 
    379     public boolean getZoneActiveStatus() {
    380         return mIsZoneActive;
    381     }
    382 
    383     public void computeZoneActiveStatus() {
    384         // init again. needed because of a profile change
    385         mIsZoneActive = false;
    386         if (mSupportsUEvent) {
    387             // Zone de-activated when any threshold for that zone is
    388             // above the allowed Max threshold.
    389             if (mMaxThreshExceeded == true) {
    390                 Log.i(TAG, "deactivate zone:" + mZoneName +
    391                         ". Zone Threshold exceeds max trip temp:" + mTripMax);
    392                 mIsZoneActive = false;
    393                 return;
    394             }
    395         }
    396         if (mZoneTempThresholds == null) {
    397             Log.i(TAG, "deactivate zone:" + getZoneName() + " threshold list is NULL! ");
    398             mIsZoneActive = false;
    399             return;
    400         }
    401         // 1. minimum number of states supported must be DEFAULT NUM STATES
    402         // 2. if sensor list null disable zone
    403         if (mMaxStates < ThermalManager.DEFAULT_NUM_ZONE_STATES) {
    404             // substract by 1 since TOFF is transparent to USER
    405             int minStateSupport = ThermalManager.DEFAULT_NUM_ZONE_STATES - 1;
    406             Log.i(TAG, "deactivate zone:" + getZoneName() + " supports < "
    407                     + minStateSupport + " states");
    408             mIsZoneActive = false;
    409             return;
    410         }
    411         if (mThermalSensors == null) {
    412             Log.i(TAG, "deactivate zone:" + getZoneName() + " sensor list null! ");
    413             mIsZoneActive = false;
    414             return;
    415         }
    416 
    417         if (mSupportsUEvent) {
    418             // if uevent just check the first sensor
    419             ThermalSensor s = mThermalSensors.get(0);
    420             if (s != null && s.getSensorActiveStatus()) {
    421                 mIsZoneActive = true;
    422                 return;
    423             }
    424         } else {
    425             if (mPollDelay == null) {
    426                 Log.i(TAG, "deactivate zone:" + getZoneName()
    427                         + " polldelay list null in poll mode! ");
    428                 mIsZoneActive = false;
    429                 return;
    430             }
    431             if (mZoneTempThresholds.length != mPollDelay.length) {
    432                 Log.i(TAG, "deactivate zone:" + getZoneName()
    433                         + " mismatch of polldelay and threshold list in polling mode!");
    434                 mIsZoneActive = false;
    435                 return;
    436             }
    437             for (ThermalSensor ts : mThermalSensors) {
    438                 if (ts != null && ts.getSensorActiveStatus()) {
    439                     mIsZoneActive = true;
    440                     return;
    441                 }
    442             }
    443         }
    444     }
    445 
    446     public void setEmulTempFlag(int flag) {
    447         mSupportsEmulTemp = (flag == 1);
    448     }
    449 
    450     public boolean getEmulTempFlag() {
    451         return mSupportsEmulTemp;
    452     }
    453 
    454     // override in Specific zone class which inherit ThermalZone
    455     public void startMonitoring() {
    456     }
    457 
    458     // override in Specific zone class which inherit ThermalZone
    459     public void stopMonitoring() {
    460     }
    461 
    462     // override in ModemZone to unregister Modem specific intents
    463     // override in VirtualThermalZone to stop UEvent observers
    464     public void unregisterReceiver() {
    465         if (isUEventSupported()) {
    466             mUEventObserver.stopObserving();
    467         }
    468     }
    469 
    470     // override in VirtualThermalZone class
    471     public void startEmulTempObserver() {
    472     }
    473 
    474     // override in VirtualThermalZone class
    475     public void calibrateThresholds() {
    476     }
    477 
    478     /**
    479      * Function that calculates the state of the Thermal Zone after reading
    480      * temperatures of all sensors in the zone. This function is used when a
    481      * zone operates in polling mode.
    482      */
    483     public boolean isZoneStateChanged() {
    484         for (int i = 0; i < mThermalSensors.size(); i++) {
    485             if (mThermalSensors.get(i).getSensorActiveStatus()) {
    486                 mThermalSensors.get(i).updateSensorTemp();
    487             }
    488         }
    489         return updateZoneParams();
    490     }
    491 
    492     /**
    493      * Function that calculates the state of the Thermal Zone after reading
    494      * temperatures of all sensors in the zone. This is an overloaded function
    495      * used when a zone supports UEvent notifications from kernel. When a
    496      * sensor sends an UEvent, it also sends its current temperature as a
    497      * parameter of the UEvent.
    498      */
    499     public boolean isZoneStateChanged(ThermalSensor s, int temp) {
    500         if (s == null) return false;
    501         s.setCurrTemp(temp);
    502         setZoneTemp(temp);
    503         return updateZoneParams();
    504     }
    505 
    506     /**
    507      * Method to update Zone Temperature and Zone Thermal State
    508      */
    509     public boolean updateZoneParams() {
    510         int newZoneState;
    511         int prevZoneState = mCurrThermalState;
    512 
    513         if (!updateZoneTemp()) {
    514             return false;
    515         }
    516 
    517         newZoneState = ThermalUtils.calculateThermalState(mZoneTemp, mZoneTempThresholds);
    518         if (newZoneState == prevZoneState) {
    519             return false;
    520         }
    521 
    522         if (newZoneState == ThermalManager.THERMAL_STATE_OFF) {
    523             setZoneState(newZoneState);
    524             return true;
    525         }
    526 
    527         int threshold = ThermalUtils.getLowerThresholdTemp(prevZoneState, mZoneTempThresholds);
    528         // For Interrupt based zones, HW (should) takes care of the debounce.
    529         if (!isUEventSupported()) {
    530             if (newZoneState < prevZoneState && getZoneTemp() > (threshold - getDBInterval())) {
    531                 Log.i(TAG, " THERMAL_LOW_EVENT for zone:" + getZoneName()
    532                         + " rejected due to debounce interval");
    533                 return false;
    534             }
    535         }
    536 
    537         setZoneState(newZoneState);
    538         setEventType(newZoneState > prevZoneState
    539                 ? ThermalManager.THERMAL_HIGH_EVENT
    540                 : ThermalManager.THERMAL_LOW_EVENT);
    541         return true;
    542     }
    543 
    544     public boolean updateZoneTemp() {
    545         return false;
    546     }
    547 
    548     public void registerUevent() {
    549         int indx;
    550 
    551         if (mThermalSensors == null) return;
    552         if (mThermalSensors.size() > 1) {
    553             Log.i(TAG, "for zone:" + getZoneName() + " in uevent mode only first sensor used!");
    554         }
    555         ThermalSensor sensor = mThermalSensors.get(0);
    556         if (sensor == null) return;
    557         String path = sensor.getUEventDevPath();
    558         if (path.equalsIgnoreCase("invalid")) return;
    559         // first time update of sensor temp and zone temp
    560         sensor.updateSensorTemp();
    561         setZoneTemp(sensor.getCurrTemp());
    562         if (updateZoneParams()) {
    563             // first intent after initialization
    564             sendThermalEvent();
    565         }
    566         mUEventObserver.startObserving(path);
    567         programThresholds(sensor);
    568     }
    569 
    570     public UEventObserver mUEventObserver = new UEventObserver() {
    571         @Override
    572         public void onUEvent(UEventObserver.UEvent event) {
    573             String sensorName;
    574             int sensorTemp, errorVal, eventType = -1;
    575             ThermalZone zone;
    576             if (mThermalSensors ==  null) return;
    577 
    578             // Name of the sensor and current temperature are mandatory parameters of an UEvent
    579             sensorName = event.get("NAME");
    580             sensorTemp = Integer.parseInt(event.get("TEMP"));
    581 
    582             // eventType is an optional parameter. so, check for null case
    583             if (event.get("EVENT") != null)
    584                 eventType = Integer.parseInt(event.get("EVENT"));
    585 
    586             if (sensorName != null) {
    587                 Log.i(TAG, "UEvent received for sensor:" + sensorName + " temp:" + sensorTemp);
    588                 // check the name against the first sensor
    589                 ThermalSensor sensor = mThermalSensors.get(0);
    590                 if (sensor != null && sensor.getSensorName() != null
    591                         && sensor.getSensorName().equalsIgnoreCase(sensorName)) {
    592                     // Adjust the sensor temperature based on the 'error correction' temperature.
    593                     // For 'LOW' event, debounce interval will take care of this.
    594                     errorVal = sensor.getErrorCorrectionTemp();
    595                     if (eventType == ThermalManager.THERMAL_HIGH_EVENT)
    596                         sensorTemp += errorVal;
    597 
    598                     if (isZoneStateChanged(sensor, sensorTemp)) {
    599                         sendThermalEvent();
    600                         // reprogram threshold
    601                         programThresholds(sensor);
    602                     }
    603                 }
    604             }
    605         }
    606     };
    607 
    608     public void programThresholds(ThermalSensor s) {
    609         if (s == null) return;
    610         int zoneState = getZoneState();
    611         if (zoneState == ThermalManager.THERMAL_STATE_OFF) return;
    612         int lowerTripPoint = ThermalUtils.getLowerThresholdTemp(zoneState, getZoneTempThreshold());
    613         int upperTripPoint = ThermalUtils.getUpperThresholdTemp(zoneState, getZoneTempThreshold());
    614         if (lowerTripPoint != ThermalManager.INVALID_TEMP
    615                 && upperTripPoint != ThermalManager.INVALID_TEMP) {
    616             if (ThermalUtils.writeSysfs(s.getSensorLowTempPath(), lowerTripPoint) == -1) {
    617                 Log.i(TAG, "error while programming lower trip point:" + lowerTripPoint
    618                         + "for sensor:" + s.getSensorName());
    619             }
    620             if (ThermalUtils.writeSysfs(s.getSensorHighTempPath(), upperTripPoint) == -1) {
    621                 Log.i(TAG, "error while programming upper trip point:" + upperTripPoint
    622                         + "for sensor:" + s.getSensorName());
    623             }
    624         }
    625     }
    626 
    627     public void sendThermalEvent() {
    628         ThermalEvent event = new ThermalEvent(mZoneID, mCurrEventType,
    629                 mCurrThermalState, mZoneTemp, mZoneName,
    630                 ThermalManager.getCurProfileName());
    631         ThermalManager.addThermalEvent(event);
    632     }
    633 }
    634