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
17package com.intel.thermal;
18
19import android.content.Context;
20import android.content.Intent;
21import android.os.SystemProperties;
22import android.os.UserHandle;
23import android.util.Log;
24
25import java.io.File;
26import java.io.IOException;
27import java.lang.NumberFormatException;
28import java.lang.StringBuilder;
29import java.util.ArrayList;
30import java.util.concurrent.ArrayBlockingQueue;
31import java.util.concurrent.BlockingQueue;
32import java.util.Enumeration;
33import java.util.Hashtable;
34import java.util.Iterator;
35import java.util.Map;
36import java.util.NoSuchElementException;
37/**
38 * The ThermalManager class contains data structures that are common to both
39 * Thermal Sensor/Zone and Cooling device parts.
40 *
41 * @hide
42 */
43public class ThermalManager {
44    private static final String TAG = "ThermalManager";
45    private static Context sContext;
46    private static String sVersion;
47    private static String sCurProfileName;
48    private static String sProfileNameList;
49    private static int sProfileCount;
50    private static final String ITUX_VERSION_PROPERTY = "ro.thermal.ituxversion";
51    /* Parameter needed for reading configuration files */
52    public static final String SENSOR_FILE_NAME = "thermal_sensor_config.xml";
53    public static final String THROTTLE_FILE_NAME = "thermal_throttle_config.xml";
54    public static final String DEFAULT_DIR_PATH = "/system/etc/";
55    public static final String DEBUG_DIR_PATH = "/data/";
56    public static String sSensorFilePath;
57    public static String sThrottleFilePath;
58    /* *XmlId's are assigned if config files are choosen from overlays */
59    public static int sSensorFileXmlId = -1;
60    public static int sThrottleFileXmlId = -1;
61    /* Set to true if config are available in DEFAULT or DEBUG path */
62    public static boolean sIsConfigFiles = false;
63    /* Whether we are using the config files from overlays directory or from /etc/ */
64    public static boolean sIsOverlays = false;
65    /* Parameters required for MaxTrip data */
66    public static final String TJMAX_PATH = "/sys/devices/platform/coretemp.0/temp2_crit";
67    public static final int sDefaultTjMax = 90000;
68    public static int sTjMaxTemp;
69    public static final int sMaxSkinTrip = 150000;
70
71    public static String sUEventDevPath = "DEVPATH=/devices/virtual/thermal/thermal_zone";
72    /**
73     * Thermal Zone State Changed Action: This is broadcast when the state of a
74     * thermal zone changes.
75     */
76    public static final String ACTION_THERMAL_ZONE_STATE_CHANGED =
77            "com.intel.thermal.action.THERMAL_ZONE_STATE_CHANGED";
78
79    public static PlatformInfo sPlatformInfo;
80    public static ThermalCooling sCoolingManager;
81    /* List of Thermal zones for current profile. Access protected by 'sProfileSwitchLock' */
82    private static ArrayList<ThermalZone> sThermalZonesList;
83
84    /* Hashtable of (ProfileName and ListOfZonesUnderThisProfile) */
85    public static Hashtable<String, ArrayList<ThermalZone>> sProfileZoneMap =
86            new Hashtable<String, ArrayList<ThermalZone>>();
87
88    /**
89     * This holds the map for the current profile. Access protected by 'sProfileSwitchLock'.
90     * Should be initialized for every profile change.
91     */
92    private static Hashtable<Integer, ZoneCoolerBindingInfo> sZoneCoolerBindMap =
93            new Hashtable<Integer, ZoneCoolerBindingInfo>();
94
95    /* Hashtable of (ProfileName and Hashtable(zoneID, ZoneCoolerBindingInfo) object */
96    public static Hashtable<String, Hashtable<Integer, ZoneCoolerBindingInfo>> sProfileBindMap =
97            new Hashtable<String, Hashtable<Integer, ZoneCoolerBindingInfo>>();
98
99    /* Hashtable of (Cooling Device ID and ThermalCoolingDevice object) */
100    public static Hashtable<Integer, ThermalCoolingDevice> sCDevMap =
101            new Hashtable<Integer, ThermalCoolingDevice>();
102
103    /* Hashtable of sensor name and sensor object */
104    public static Hashtable<String, ThermalSensor> sSensorMap =
105            new Hashtable<String, ThermalSensor>();
106
107    public static final int CRITICAL_TRUE = 1;
108    public static final int CRITICAL_FALSE = 0;
109    /* sZoneCriticalPendingMap stores info whether a zone is in critical state and platform
110     * shutdown has not yet occured due to some scenario like ongoing emergency call
111     **/
112    public static Hashtable<Integer, Integer> sZoneCriticalPendingMap = null;
113    /* this lock is to access sZoneCriticalPendingMap synchronously */
114    private static final Object sCriticalPendingLock = new Object();
115    /* this count keeps track of number of zones in pending critical state.When
116     * sZoneCriticalPendingMap is updated, the count is either incremented or
117     * decremented depending on whether criical pending flag for a zone is true/
118     * false. By keeping a count we can avoid scanning through the entire map to
119     * see if there is a pending critical shutdown
120     **/
121    private static int sCriticalZonesCount = 0;
122
123    /* Blocking queue to hold thermal events from thermal zones */
124    private static final int EVENT_QUEUE_SIZE = 10;
125
126    public static BlockingQueue<ThermalEvent> sEventQueue = new ArrayBlockingQueue<ThermalEvent>(EVENT_QUEUE_SIZE);
127    /* this lock is to handle uevent callbacks synchronously */
128    private static final Object sLock = new Object();
129
130    /**
131     * Extra for {@link ACTION_THERMAL_ZONE_STATE_CHANGED}:
132     * integer containing the thermal zone.
133     */
134    public static final String EXTRA_ZONE = "zone";
135
136    /**
137     * Extra for {@link ACTION_THERMAL_ZONE_STATE_CHANGED}:
138     * integer containing the thermal state of the zone.
139     */
140    public static final String EXTRA_STATE = "state";
141
142    /**
143     * Extra for {@link ACTION_THERMAL_ZONE_STATE_CHANGED}:
144     * integer containing the thermal event type for the zone.
145     */
146    public static final String EXTRA_EVENT = "event";
147
148    /**
149     * Extra for {@link ACTION_THERMAL_ZONE_STATE_CHANGED}:
150     * integer containing the temperature of the zone.
151     */
152    public static final String EXTRA_TEMP = "temp";
153    public static final String ACTION_CHANGE_THERMAL_PROFILE =
154            "android.intent.action.CHANGE_THERMAL_PROFILE";
155    /**
156     * Extra for {@link ACTION_THERMAL_ZONE_STATE_CHANGED}:
157     * String containing the name of the zone.
158     */
159    public static final String EXTRA_NAME = "name";
160    public static final String EXTRA_PROFILE = "Profile";
161
162    private static Intent sQueryProfileIntent;
163    public static final String ACTION_QUERY_THERMAL_PROFILE =
164            "com.intel.thermal.action.QUERY_THERMAL_PROFILE";
165    public static final String ACTION_KILL = "kill";
166
167    /**
168     * Integer containing the number of thermal profiles.
169     */
170    public static final String EXTRA_NUM_PROFILE = "NumProfiles";
171    /**
172     * Space separated string containing list of thermal profile names.
173     */
174    public static final String EXTRA_PROFILE_LIST = "ProfileList";
175    /**
176     * String containing current thermal profile name.
177     */
178    public static final String EXTRA_CUR_PROFILE = "CurProfile";
179
180    /* values for "STATE" field in the THERMAL_STATE_CHANGED Intent */
181    public static final int THERMAL_STATE_OFF = -1;
182
183    public static final int THERMAL_STATE_NORMAL = 0;
184
185    public static final int THERMAL_STATE_WARNING = 1;
186
187    public static final int THERMAL_STATE_ALERT = 2;
188
189    public static final int THERMAL_STATE_CRITICAL = 3;
190
191    public static final int DEFAULT_NUM_THROTTLE_VALUES = 4;
192
193    // 5 including TOFF and TCRITICAL
194    public static final int DEFAULT_NUM_ZONE_STATES = 5;
195
196    public static final String STATE_NAMES[] = {
197            "OFF", "NORMAL", "WARNING", "ALERT", "CRITICAL"
198    };
199
200    /* values of the "EVENT" field in the THERMAL_STATE_CHANGED intent */
201    /* Indicates type of event */
202    public static final int THERMAL_LOW_EVENT = 0;
203
204    public static final int THERMAL_HIGH_EVENT = 1;
205
206    public static final int THERMAL_EMUL_TEMP_EVENT = 2;
207
208    public static final int INVALID_TEMP = 0xDEADBEEF;
209
210    /* Absolute zero in millidegree C */
211    public static final int ABS_ZERO = -273000;
212
213    /* base sysfs path for sensors */
214    public static final String sSysfsSensorBasePath = "/sys/class/thermal/thermal_zone";
215
216    public static final String sSysfsSensorHighTempPath = "trip_point_1_temp";
217
218    public static final String sSysfsSensorLowTempPath = "trip_point_0_temp";
219
220    public static final String sCoolingDeviceBasePath = "/sys/class/thermal/cooling_device";
221
222    public static final String sCoolingDeviceState = "/cur_state";
223
224    public static final int THROTTLE_MASK_ENABLE = 1;
225
226    public static final int DETHROTTLE_MASK_ENABLE = 1;
227
228    /**
229     * Magic number (agreed upon between the Thermal driver and the Thermal Service)
230     * symbolising Dynamic Turbo OFF
231     */
232    public static final int DISABLE_DYNAMIC_TURBO = 0xB0FF;
233
234    public static boolean sIsDynamicTurboEnabled = false;
235
236    /* thermal notifier system properties for shutdown action */
237    public static boolean sShutdownTone = false;
238
239    public static boolean sShutdownToast = false;
240
241    public static boolean sShutdownVibra = false;
242
243    /* Name of default Thermal Profile */
244    public static final String DEFAULT_PROFILE_NAME = "Default";
245
246    /* Lock protecting profile-switch */
247    private static final Object sProfileSwitchLock = new Object();
248
249    /**
250     * This class stores the zone throttle info. It contains the zoneID,
251     * CriticalShutdown flag and CoolingDeviceInfo arraylist.
252     */
253    public static class ZoneCoolerBindingInfo {
254        private int mZoneID;
255        // max states includes TOFF also.
256        // if user provides k threshold values in XML.
257        // mMaxStates = k + 1(for critical) + 1(for TOFF)
258        // this is same as the max states stored in corresponding zone object
259        protected int mMaxStates;
260        private int mIsCriticalActionShutdown;
261
262        /* cooler ID mask, 1 - throttle device, 0- no action, -1- dont care */
263        private ArrayList<CoolingDeviceInfo> mCoolingDeviceInfoList = null;
264
265        // ManyToOneMapping: ZoneStates >= CoolingDeviceStates
266        private ArrayList<Integer> mZoneToCoolDevBucketSize = null;
267
268        // OneToOneMapping: CoolingDeviceStates >= ThrottleValues
269        private ArrayList<Integer> mCoolDevToThrottBucketSize = null;
270
271        private CoolingDeviceInfo lastCoolingDevInfoInstance = null;
272
273        public ZoneCoolerBindingInfo() {
274            mZoneToCoolDevBucketSize = new ArrayList<Integer>();
275            mCoolDevToThrottBucketSize = new ArrayList<Integer>();
276        }
277
278        public int getLastState() {
279            // mMaxStates = k + 1(for critical) + 1(for TOFF)
280            return mMaxStates - 2;
281        }
282
283        public void setMaxStates(int state) {
284            mMaxStates = state;
285        }
286
287        public int getMaxStates() {
288            return mMaxStates;
289        }
290
291        public void setZoneToCoolDevBucketSize() {
292            int size = 1;
293            int zoneStates = getMaxStates();
294            for (CoolingDeviceInfo coolDev : mCoolingDeviceInfoList) {
295                size = (zoneStates - 1) / coolDev.getCoolingDeviceStates();
296                mZoneToCoolDevBucketSize.add(size == 0 ? 1 : size);
297            }
298        }
299
300        public int getZoneToCoolDevBucketSizeIndex(int index) {
301            if (mZoneToCoolDevBucketSize.size() > index)
302                return mZoneToCoolDevBucketSize.get(index);
303
304            return 1;
305        }
306
307        public int getCoolDevToThrottBucketSizeIndex(int index) {
308            if (mZoneToCoolDevBucketSize.size() > index)
309                return mCoolDevToThrottBucketSize.get(index);
310
311            return 1;
312        }
313
314        public void setCoolDevToThrottBucketSize() {
315            int size = 1;
316            for (CoolingDeviceInfo coolDev : mCoolingDeviceInfoList) {
317                size = coolDev.getMaxThrottleStates() / coolDev.getCoolingDeviceStates();
318                mCoolDevToThrottBucketSize.add(size == 0 ? 1 : size);
319            }
320        }
321
322        public void printAttributes() {
323            if (mCoolingDeviceInfoList == null) return;
324            StringBuilder s = new StringBuilder();
325            for (CoolingDeviceInfo c : mCoolingDeviceInfoList) {
326                if (c != null) {
327                    s.append(c.getCoolingDeviceId());
328                    s.append(",");
329                }
330            }
331            Log.i(TAG, "zone id:" + mZoneID + " coolingDevID  mapped:" + s.toString());
332        }
333
334        public void printMappedAttributes() {
335            if (mZoneToCoolDevBucketSize == null || mCoolDevToThrottBucketSize == null) return;
336            StringBuilder s = new StringBuilder();
337            for (int bs : mZoneToCoolDevBucketSize) {
338                s.append(bs);
339                s.append(",");
340            }
341            Log.i(TAG, "zone id:" + mZoneID + " ZoneToCoolDevBucketSize:" + s.toString());
342            // clear the string
343            s.delete(0,s.length());
344            for (int bs : mCoolDevToThrottBucketSize) {
345                s.append(bs);
346                s.append(",");
347            }
348            Log.i(TAG, "zone id:" + mZoneID + " CoolDevToThrottBucketSize:" + s.toString());
349        }
350
351        public class CoolingDeviceInfo {
352            private int mCDeviceID;
353
354            // mCoolingDeviceState is number of device states exposed under a zone.
355            // this must be less than or equal to its total number of throttle values
356            private int mCoolingDeviceStates = DEFAULT_NUM_THROTTLE_VALUES;
357
358            // store a copy here for fast lookup during throttling/dethrottling
359            private int mMaxThrottleStates = 0;
360            private ArrayList<Integer> mDeviceThrottleMask = null;
361
362            private ArrayList<Integer> mDeviceDethrottleMask = null;
363
364            public CoolingDeviceInfo() {
365            }
366
367            public int getMaxThrottleStates() {
368                return mMaxThrottleStates;
369            }
370
371            public boolean checkMaskList(int throttleStates) {
372                boolean ret = true;
373                // if the list is empty this mean, THROTTLE MASK and/or
374                // DETHTOTTLE mask was not provided. Initialize default mask.
375                if (mDeviceThrottleMask ==  null) {
376                    mDeviceThrottleMask = new ArrayList<Integer>();
377                    for (int i = 0; i < mCoolingDeviceStates; i++) {
378                        mDeviceThrottleMask.add(THROTTLE_MASK_ENABLE);
379                    }
380                } else if (mDeviceThrottleMask.size() != mCoolingDeviceStates) {
381                    Log.i(TAG, "cdevid:" + mCDeviceID
382                            + " has mismatch in Cooling device state and mask array!deactivate!");
383                    ret = false;
384                }
385
386                if (mDeviceDethrottleMask ==  null) {
387                    mDeviceDethrottleMask = new ArrayList<Integer>();
388                    for (int i = 0; i < mCoolingDeviceStates; i++) {
389                        mDeviceDethrottleMask.add(DETHROTTLE_MASK_ENABLE);
390                    }
391                } else if (mDeviceDethrottleMask.size() != mCoolingDeviceStates) {
392                    Log.i(TAG, "cdevid:" + mCDeviceID
393                            + " has mismatch in Cooling device state and mask array!deactivate!");
394                    ret = false;
395                }
396                if (ret) {
397                    mMaxThrottleStates = throttleStates;
398                }
399                return ret;
400            }
401
402            public int getCoolingDeviceId() {
403                return mCDeviceID;
404            }
405
406            public void setCoolingDeviceId(int deviceID) {
407                mCDeviceID = deviceID;
408            }
409
410            public int getCoolingDeviceStates() {
411                return mCoolingDeviceStates;
412            }
413
414            public void setCoolingDeviceStates(int num) {
415                mCoolingDeviceStates = num;
416            }
417
418            public ArrayList<Integer> getThrottleMaskList() {
419                return mDeviceThrottleMask;
420            }
421
422            public ArrayList<Integer> getDeThrottleMaskList() {
423                return mDeviceDethrottleMask;
424            }
425
426            public void setThrottleMaskList(ArrayList<Integer> list) {
427                this.mDeviceThrottleMask = list;
428            }
429
430            public void setDeThrottleMaskList(ArrayList<Integer> list) {
431                this.mDeviceDethrottleMask = list;
432            }
433
434        }
435
436        public ArrayList<CoolingDeviceInfo> getCoolingDeviceInfoList() {
437            return mCoolingDeviceInfoList;
438        }
439
440        public void createNewCoolingDeviceInstance() {
441            lastCoolingDevInfoInstance = new CoolingDeviceInfo();
442        }
443
444        public CoolingDeviceInfo getLastCoolingDeviceInstance() {
445            return lastCoolingDevInfoInstance;
446        }
447
448        public void setZoneID(int zoneID) {
449            mZoneID = zoneID;
450        }
451
452        public int getZoneID() {
453            return mZoneID;
454        }
455
456        public void setCriticalActionShutdown(int val) {
457            mIsCriticalActionShutdown = val;
458        }
459
460        public int getCriticalActionShutdown() {
461            return mIsCriticalActionShutdown;
462        }
463
464        public void setCoolingDeviceInfoList(ArrayList<CoolingDeviceInfo> devinfoList) {
465            mCoolingDeviceInfoList = devinfoList;
466        }
467
468        public void initializeCoolingDeviceInfoList() {
469            mCoolingDeviceInfoList = new ArrayList<CoolingDeviceInfo>();
470        }
471
472        public void addCoolingDeviceToList(CoolingDeviceInfo CdeviceInfo) {
473            mCoolingDeviceInfoList.add(CdeviceInfo);
474        }
475    }
476
477    /* platform information */
478    public static class PlatformInfo {
479       public int mMaxThermalStates;
480
481       public int getMaxThermalStates() {
482            return mMaxThermalStates;
483       }
484
485       public void printAttrs() {
486           Log.i(TAG, Integer.toString(mMaxThermalStates));
487       }
488       public PlatformInfo() {}
489    }
490
491    /* methods */
492    public ThermalManager() {
493        // empty constructor
494    }
495
496    public static void setContext(Context context) {
497        sContext = context;
498    }
499
500    public static String getVersion() {
501        return sVersion;
502    }
503
504    public static void loadiTUXVersion() {
505        sVersion = SystemProperties.get(ITUX_VERSION_PROPERTY, "none");
506        if (sVersion.equalsIgnoreCase("none")) {
507            Log.i(TAG, "iTUX Version not found!");
508        } else {
509            Log.i(TAG, "iTUX Version:" + sVersion);
510        }
511    }
512
513    public static void addThermalEvent(ThermalEvent event) {
514        try {
515            ThermalManager.sEventQueue.put(event);
516        } catch (InterruptedException ex) {
517            Log.i(TAG, "caught InterruptedException in posting to event queue");
518        }
519    }
520
521    public static void setCurBindMap(String profName) {
522        synchronized (sProfileSwitchLock) {
523            sZoneCoolerBindMap = sProfileBindMap.get(profName);
524        }
525    }
526
527    public static Hashtable<Integer, ZoneCoolerBindingInfo> getCurBindMap() {
528        synchronized (sProfileSwitchLock) {
529            return sZoneCoolerBindMap;
530        }
531    }
532
533    public static Hashtable<Integer, ZoneCoolerBindingInfo> getBindMap(String profName) {
534        return sProfileBindMap.get(profName);
535    }
536
537    private static void setCurProfileName(String profName) {
538        sCurProfileName = profName;
539    }
540
541    public static String getCurProfileName() {
542        return sCurProfileName;
543    }
544
545    private static boolean isProfileExists(String profName) {
546        if (sProfileZoneMap.get(profName) == null || sProfileBindMap.get(profName) == null) {
547            return false;
548        }
549        return true;
550    }
551
552    private static void startNewProfile(String profName) {
553        sThermalZonesList = sProfileZoneMap.get(profName);
554        sZoneCoolerBindMap = sProfileBindMap.get(profName);
555        if (sThermalZonesList == null || sZoneCoolerBindMap == null) {
556            Log.i(TAG, "Couldn't shift to profile:" + profName);
557            return;
558        }
559        initializeZoneCriticalPendingMap();
560        setCurProfileName(profName);
561        int activeZones = startMonitoringZones();
562        Log.i(TAG, activeZones + " zones found active in profile " + profName);
563        // broadcast a sticky intent for the clients
564        sendQueryProfileIntent();
565    }
566
567    public static void stopCurrentProfile() {
568        for (ThermalZone zone : sThermalZonesList) {
569            // Stop Polling threads
570            zone.stopMonitoring();
571            // Unregister UEvent/EmulTemp observers
572            zone.unregisterReceiver();
573            // Reset Parameters:
574            // Zone State: Normal, Event Type: LOW, Temperature: Normal Threshold
575            zone.setZoneState(0);
576            zone.setEventType(ThermalManager.THERMAL_LOW_EVENT);
577            zone.setZoneTemp(zone.getZoneTempThreshold(0));
578            // Send ThermalIntent with above parameters
579            // This will release all throttle controls this zone had.
580            // Since we are in the middle of a profile switch(stop),
581            // set the override parameter as true, so that this
582            // event is actually queued for processing.
583            // TODO: Find a way to take care of zones that are not
584            // present in thermal_sensor_config.xml but present in
585            // thermal_throttle_config.xml (usually from other components)
586            zone.sendThermalEvent();
587            // Reprogram the sensor thresholds if this zone supported interrupts
588            // TODO: We are reprogramming the calibrated thresholds in case the
589            // the sensor was using 'weights' and 'offset'. Hope this is fine.
590            if (zone.isUEventSupported()) {
591                zone.programThresholds((zone.getThermalSensorList()).get(0));
592            }
593        }
594    }
595
596    public static void startDefaultProfile() {
597        if (isProfileExists(DEFAULT_PROFILE_NAME)) {
598            startNewProfile(DEFAULT_PROFILE_NAME);
599        }
600        // register for Thermal Profile Change Intent only after
601        // we have started the default profile
602        sCoolingManager.registerProfChangeListener();
603    }
604
605    public static void changeThermalProfile(String newProfName) {
606        synchronized (sProfileSwitchLock) {
607            if (newProfName.equalsIgnoreCase(sCurProfileName)) {
608                Log.i(TAG, "New Profile same as current profile. Profile change request Ignored");
609                return;
610            }
611            if (!isProfileExists(newProfName)) {
612                Log.i(TAG, "New Profile does not exist in xml. Profile change request Ignored");
613                return;
614            }
615            Log.i(TAG, "ACTION_CHANGE_THERMAL_PROFILE received. New Profile: " + newProfName);
616
617            stopCurrentProfile();
618            startNewProfile(newProfName);
619        }
620    }
621
622    public static void setBucketSizeForProfiles() {
623        Iterator it = ThermalManager.sProfileZoneMap.entrySet().iterator();
624        while (it.hasNext()) {
625            Map.Entry entryProfZone = (Map.Entry) it.next();
626            String keyProfile = (String) entryProfZone.getKey();
627            sThermalZonesList = (ArrayList<ThermalZone>) entryProfZone.getValue();
628            setCurBindMap(keyProfile);
629            for (ThermalZone zone : sThermalZonesList) {
630                if (sZoneCoolerBindMap == null) {
631                    Log.e(TAG, "ZoneCoolerBindMap null while setBucketSizeForProfiles");
632                    return;
633                }
634                ZoneCoolerBindingInfo bindInfo = sZoneCoolerBindMap.get(zone.getZoneId());
635                if (bindInfo == null) {
636                    Log.e(TAG, "CoolerBindingInfo for zoneid:" + zone.getZoneId() + "not mapped");
637                    return;
638                }
639                bindInfo.setMaxStates(zone.getMaxStates());
640                bindInfo.setZoneToCoolDevBucketSize();
641                bindInfo.setCoolDevToThrottBucketSize();
642                if (zone.isUEventSupported()) {
643                    // calibration of thresholds based on weight, order
644                    if (!zone.isMaxThreshExceed())
645                        zone.calibrateThresholds();
646                }
647            }
648        }
649    }
650
651    public static int startMonitoringZones() {
652        int activeZonesCount = 0;
653        for (ThermalZone zone : sThermalZonesList) {
654            zone.computeZoneActiveStatus();
655            if (zone.getZoneActiveStatus() == false) {
656                Log.i(TAG, "deactivating inactive zone:" + zone.getZoneName());
657                continue;
658            }
659
660            ZoneCoolerBindingInfo bindInfo = sZoneCoolerBindMap.get(zone.getZoneId());
661            if (bindInfo != null) {
662                // TODO: To be conditioned under debug
663                bindInfo.printMappedAttributes();
664            }
665            if (zone.isUEventSupported()) {
666                zone.registerUevent();
667            } else {
668                // start polling thread for each zone
669                zone.startMonitoring();
670            }
671            zone.startEmulTempObserver();
672            activeZonesCount++;
673        }
674        return activeZonesCount;
675    }
676
677    public static void readShutdownNotiferProperties() {
678        try {
679            if ("1".equals(SystemProperties.get("persist.thermal.shutdown.msg", "0"))) {
680                sShutdownToast = true;
681            }
682            if ("1".equals(SystemProperties.get("persist.thermal.shutdown.tone", "0"))) {
683                sShutdownTone = true;
684            }
685            if ("1".equals(SystemProperties.get("persist.thermal.shutdown.vibra", "0"))) {
686                sShutdownVibra = true;
687            }
688        } catch (java.lang.IllegalArgumentException e) {
689            Log.e(TAG, "exception caught in reading thermal system properties");
690        }
691    }
692
693    private static void initializeZoneCriticalPendingMap() {
694        sZoneCriticalPendingMap = new Hashtable<Integer, Integer>();
695        if (sZoneCriticalPendingMap == null) return;
696        Enumeration en;
697        try {
698            // look up for zone list is performed from sZoneCoolerBindMap instead of
699            // sThermalZonesList since some non thermal zones may not have entry in
700            // sThermalZonesList. This is because such zones only have entry in throttle
701            // config file and not in sensor config files.
702            // 'sZoneCoolerBindMap' is protected by caller here.
703            en = sZoneCoolerBindMap.keys();
704            while (en.hasMoreElements()) {
705                int zone = (Integer) en.nextElement();
706                sZoneCriticalPendingMap.put(zone, CRITICAL_FALSE);
707            }
708        } catch (NoSuchElementException e) {
709            Log.i(TAG, "NoSuchElementException in InitializeZoneCriticalPendingMap()");
710        }
711    }
712
713    /*
714     * updateZoneCriticalPendingMap updates sZoneCriticalPendingMap synchronously.
715     * sCriticalZonesCount is incremented iff old value in the map for the zone is
716     * FALSE (ensures count is incremented only once for a zone) and decremented
717     * iff oldval is TRUE (ensures no negative value for count)
718     **/
719    public static boolean updateZoneCriticalPendingMap(int zoneid, int flag) {
720        synchronized (sCriticalPendingLock) {
721            if (sZoneCriticalPendingMap == null) return false;
722                Integer oldVal = sZoneCriticalPendingMap.get(zoneid);
723                if (oldVal == null) return false;
724                sZoneCriticalPendingMap.put(zoneid, flag);
725                if (oldVal == CRITICAL_FALSE && flag == CRITICAL_TRUE) {
726                   sCriticalZonesCount++;
727                } else if (oldVal == CRITICAL_TRUE && flag == CRITICAL_FALSE) {
728                   sCriticalZonesCount--;
729                }
730                return true;
731        }
732    }
733
734    public static boolean checkShutdownCondition() {
735        synchronized (sCriticalPendingLock) {
736           return sCriticalZonesCount > 0;
737        }
738    }
739
740    public static ThermalSensor getSensor(String sensorName) {
741        if (sensorName == null || sSensorMap == null) return null;
742        return sSensorMap.get(sensorName);
743    }
744
745    public static void buildProfileNameList() {
746        int count = 0;
747        StringBuilder s = new StringBuilder();
748        Iterator it = sProfileZoneMap.entrySet().iterator();
749        while (it.hasNext()) {
750            Map.Entry entry = (Map.Entry) it.next();
751            String key = (String) entry.getKey();
752            // create list of only valid profiles
753            if (isProfileExists(key)) {
754                // build a space seperate list of string
755                s.append(key);
756                s.append(" ");
757                count++;
758            }
759        }
760
761        sProfileNameList = s.toString();
762        sProfileCount = count;
763        Log.i(TAG, "profile name list:" + sProfileNameList);
764        Log.i(TAG, "profile count:" + sProfileCount);
765    }
766
767    public static void initializeStickyIntent() {
768        sQueryProfileIntent = new Intent();
769        sQueryProfileIntent.setAction(ACTION_QUERY_THERMAL_PROFILE);
770    }
771
772    private static void sendQueryProfileIntent() {
773        if (sQueryProfileIntent != null && sContext != null) {
774            sQueryProfileIntent.putExtra(ThermalManager.EXTRA_NUM_PROFILE, sProfileCount);
775            sQueryProfileIntent.putExtra(ThermalManager.EXTRA_PROFILE_LIST, sProfileNameList);
776            sQueryProfileIntent.putExtra(ThermalManager.EXTRA_CUR_PROFILE, sCurProfileName);
777            sContext.sendStickyBroadcastAsUser(sQueryProfileIntent, UserHandle.ALL);
778        }
779    }
780
781    public static void clearData() {
782        sThermalZonesList.clear();
783        // clearing hastables
784        sProfileZoneMap.clear();
785        sZoneCoolerBindMap.clear();
786        sProfileBindMap.clear();
787        sCDevMap.clear();
788        sSensorMap.clear();
789        sZoneCriticalPendingMap.clear();
790    }
791}
792