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
setMaxStates(int state)71     public void setMaxStates(int state) {
72         mMaxStates = state;
73     }
74 
updateMaxStates(int state)75     public void updateMaxStates(int state) {
76         setMaxStates(state);
77     }
78 
getMaxStates()79     public int getMaxStates() {
80         return mMaxStates;
81     }
82 
getMovingAverageFlag()83     public boolean getMovingAverageFlag() {
84         return mIsMovingAverage;
85     }
86 
setMovingAvgWindow(ArrayList<Integer> windowList)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 
movingAverageTemp()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 
printAttrs()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 
printStateThresholdMap()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 
printSensors()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 
printSensorAttribList()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 
ThermalZone()190     public ThermalZone() {
191         mCurrThermalState = ThermalManager.THERMAL_STATE_OFF;
192         mZoneTemp = ThermalManager.INVALID_TEMP;
193     }
194 
getStateAsString(int index)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 
getEventTypeAsString(int type)201     public static String getEventTypeAsString(int type) {
202         return type == 0 ? "LOW" : "HIGH";
203     }
204 
setSensorList(ArrayList<ThermalSensorAttrib> sensorAtribList)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 
getThermalSensorList()229     public ArrayList<ThermalSensor> getThermalSensorList() {
230         return mThermalSensors;
231     }
232 
getZoneState()233     public int getZoneState() {
234         return mCurrThermalState;
235     }
236 
setZoneState(int state)237     public void setZoneState(int state) {
238         mCurrThermalState = state;
239     }
240 
getEventType()241     public int getEventType() {
242         return mCurrEventType;
243     }
244 
setEventType(int type)245     public void setEventType(int type) {
246         mCurrEventType = type;
247     }
248 
setZoneTemp(int temp)249     public void setZoneTemp(int temp) {
250         mZoneTemp = temp;
251     }
252 
getZoneTemp()253     public int getZoneTemp() {
254         return mZoneTemp;
255     }
256 
setZoneId(int id)257     public void setZoneId(int id) {
258         mZoneID = id;
259     }
260 
getZoneId()261     public int getZoneId() {
262         return mZoneID;
263     }
264 
setZoneName(String name)265     public void setZoneName(String name) {
266         mZoneName = name;
267     }
268 
getZoneName()269     public String getZoneName() {
270         return mZoneName;
271     }
272 
setSupportsUEvent(int flag)273     public void setSupportsUEvent(int flag) {
274         mSupportsUEvent = (flag == 1);
275     }
276 
isUEventSupported()277     public boolean isUEventSupported() {
278         return mSupportsUEvent;
279     }
280 
isMaxThreshExceed()281     public boolean isMaxThreshExceed() {
282         return mMaxThreshExceeded;
283     }
284 
setZoneLogic(String type)285     public void setZoneLogic(String type) {
286         mZoneLogic = type;
287     }
288 
getZoneLogic()289     public String getZoneLogic() {
290         return mZoneLogic;
291     }
292 
setDBInterval(int interval)293     public void setDBInterval(int interval) {
294         mDebounceInterval = interval;
295     }
296 
getDBInterval()297     public int getDBInterval() {
298         return mDebounceInterval;
299     }
300 
getOffset()301     public int getOffset() {
302         return mOffset;
303     }
304 
setOffset(int offset)305     public void setOffset(int offset) {
306         mOffset  = offset;
307     }
308 
setPollDelay(ArrayList<Integer> delayList)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 
getPollDelay()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      */
getPollDelay(int index)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 
setZoneTempThreshold(ArrayList<Integer> thresholdList)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 
getZoneTempThreshold(int index)369     public int getZoneTempThreshold(int index) {
370         if (index < 0 || index >= mZoneTempThresholds.length)
371             return -1;
372         return mZoneTempThresholds[index];
373     }
374 
getZoneTempThreshold()375     public Integer[] getZoneTempThreshold() {
376         return mZoneTempThresholds;
377     }
378 
getZoneActiveStatus()379     public boolean getZoneActiveStatus() {
380         return mIsZoneActive;
381     }
382 
computeZoneActiveStatus()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 
setEmulTempFlag(int flag)446     public void setEmulTempFlag(int flag) {
447         mSupportsEmulTemp = (flag == 1);
448     }
449 
getEmulTempFlag()450     public boolean getEmulTempFlag() {
451         return mSupportsEmulTemp;
452     }
453 
454     // override in Specific zone class which inherit ThermalZone
startMonitoring()455     public void startMonitoring() {
456     }
457 
458     // override in Specific zone class which inherit ThermalZone
stopMonitoring()459     public void stopMonitoring() {
460     }
461 
462     // override in ModemZone to unregister Modem specific intents
463     // override in VirtualThermalZone to stop UEvent observers
unregisterReceiver()464     public void unregisterReceiver() {
465         if (isUEventSupported()) {
466             mUEventObserver.stopObserving();
467         }
468     }
469 
470     // override in VirtualThermalZone class
startEmulTempObserver()471     public void startEmulTempObserver() {
472     }
473 
474     // override in VirtualThermalZone class
calibrateThresholds()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      */
isZoneStateChanged()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      */
isZoneStateChanged(ThermalSensor s, int temp)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      */
updateZoneParams()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 
updateZoneTemp()544     public boolean updateZoneTemp() {
545         return false;
546     }
547 
registerUevent()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 
programThresholds(ThermalSensor s)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 
sendThermalEvent()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