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.app.IntentService;
20import android.app.Service;
21import android.content.BroadcastReceiver;
22import android.content.ContentResolver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.content.pm.PackageManager;
27import android.os.Handler;
28import android.os.IBinder;
29import android.os.Looper;
30import android.os.Message;
31import android.os.Process;
32import android.os.SystemProperties;
33import android.os.UserHandle;
34import android.util.Log;
35
36import java.io.BufferedReader;
37import java.io.File;
38import java.io.FileNotFoundException;
39import java.io.FileReader;
40import java.io.IOException;
41import java.lang.ClassLoader;
42import java.lang.NullPointerException;
43import java.lang.reflect.Array;
44import java.lang.SecurityException;
45import java.util.ArrayList;
46import java.util.concurrent.BlockingQueue;
47import java.util.concurrent.ArrayBlockingQueue;
48import java.util.Iterator;
49import java.util.Map;
50
51import org.xmlpull.v1.XmlPullParser;
52import org.xmlpull.v1.XmlPullParserException;
53import org.xmlpull.v1.XmlPullParserFactory;
54
55/**
56 * The ThermalService monitors the Thermal zones on the platform.
57 * The number of thermal zones and sensors associated with the zones are
58 * obtained from the thermal_sensor_config.xml file. When any thermal zone
59 * crosses the thresholds configured in the xml, a Thermal Intent is sent.
60 * ACTION_THERMAL_ZONE_STATE_CHANGED
61 * The Thermal Cooling Manager acts upon this intent and throttles
62 * the corresponding cooling device.
63 *
64 * @hide
65 */
66public class ThermalService extends Service {
67    private static final String TAG = ThermalService.class.getSimpleName();
68    private static Context mContext;
69    private Handler mHandler = new Handler();
70    static {
71        System.loadLibrary("thermalJNI");
72    }
73    protected enum MetaTag {
74            ENUM_UNKNOWN,
75            ENUM_ZONETHRESHOLD,
76            ENUM_POLLDELAY,
77            ENUM_MOVINGAVGWINDOW
78    }
79
80    public class ThermalParser {
81        // Names of the XML Tags
82        private static final String PINFO = "PlatformInfo";
83        private static final String SENSOR_ATTRIB = "SensorAttrib";
84        private static final String SENSOR = "Sensor";
85        private static final String ZONE = "Zone";
86        private static final String THERMAL_CONFIG = "thermalconfig";
87        private static final String THRESHOLD = "Threshold";
88        private static final String POLLDELAY = "PollDelay";
89        private static final String MOVINGAVGWINDOW = "MovingAverageWindow";
90        private static final String ZONELOGIC = "ZoneLogic";
91        private static final String WEIGHT = "Weight";
92        private static final String ORDER = "Order";
93        private static final String OFFSET = "Offset";
94        private static final String ZONETHRESHOLD = "ZoneThreshold";
95        private static final String PROFILE = "Profile";
96
97        private boolean mDone = false;
98        private ThermalManager.PlatformInfo mPlatformInfo = null;
99        private ThermalSensor mCurrSensor = null;
100        private ThermalZone mCurrZone = null;
101        private ArrayList<ThermalSensorAttrib> mCurrSensorAttribList = null;
102        private ThermalSensorAttrib mCurrSensorAttrib = null;
103        private ArrayList<ThermalZone> mThermalZones = null;
104        private ArrayList<Integer> mPollDelayList = null;
105        private ArrayList<Integer> mMovingAvgWindowList = null;
106        private ArrayList<Integer> mWeightList = null;
107        private ArrayList<Integer> mOrderList = null;
108        private ArrayList<Integer> mZoneThresholdList = null;
109        private String mSensorName = null;
110        XmlPullParserFactory mFactory = null;
111        XmlPullParser mParser = null;
112        int mTempZoneId = -1;
113        int mNumProfiles = 0;
114        String mTempZoneName = null;
115        String mCurProfileName = ThermalManager.DEFAULT_PROFILE_NAME;
116        FileReader mInputStream = null;
117
118        ThermalParser(String fname) {
119            try {
120                mFactory = XmlPullParserFactory.newInstance(System.
121                        getProperty(XmlPullParserFactory.PROPERTY_NAME), null);
122                mFactory.setNamespaceAware(true);
123                mParser = mFactory.newPullParser();
124            } catch (SecurityException e) {
125                Log.e(TAG, "SecurityException caught in ThermalParser");
126            } catch (IllegalArgumentException e) {
127                Log.e(TAG, "IllegalArgumentException caught in ThermalParser");
128            } catch (XmlPullParserException xppe) {
129                Log.e(TAG, "XmlPullParserException caught in ThermalParser");
130            }
131
132            try {
133                mInputStream = new FileReader(fname);
134                mPlatformInfo = null;
135                mCurrSensor = null;
136                mCurrZone = null;
137                mThermalZones = null;
138                if (mInputStream == null) return;
139                if (mParser != null) {
140                    mParser.setInput(mInputStream);
141                }
142            } catch (FileNotFoundException e) {
143                Log.e(TAG, "FileNotFoundException Exception in ThermalParser()");
144            } catch (XmlPullParserException e) {
145                Log.e(TAG, "XmlPullParserException Exception in ThermalParser()");
146            }
147        }
148
149        ThermalParser() {
150            mParser = mContext.getResources().
151                    getXml(ThermalManager.sSensorFileXmlId);
152        }
153
154        public ThermalManager.PlatformInfo getPlatformInfo() {
155            return mPlatformInfo;
156        }
157
158        public boolean parse() {
159            if (ThermalManager.sIsOverlays == false && mInputStream == null) return false;
160            /* if mParser is null, close any open stream before exiting */
161            if (mParser == null) {
162                try {
163                    if (mInputStream != null) {
164                        mInputStream.close();
165                    }
166                } catch (IOException e) {
167                    Log.i(TAG, "IOException caught in parse() function");
168                }
169                return false;
170            }
171
172            boolean ret = true;
173            MetaTag tag = MetaTag.ENUM_UNKNOWN;
174            try {
175                int mEventType = mParser.getEventType();
176                while (mEventType != XmlPullParser.END_DOCUMENT && !mDone) {
177                    switch (mEventType) {
178                        case XmlPullParser.START_DOCUMENT:
179                            Log.i(TAG, "StartDocument");
180                            break;
181                        case XmlPullParser.START_TAG:
182                            String tagName = mParser.getName();
183                            boolean isMetaTag = false;
184                            if (tagName != null && tagName.equalsIgnoreCase(ZONETHRESHOLD)) {
185                                tag = MetaTag.ENUM_ZONETHRESHOLD;
186                                isMetaTag = true;
187                            } else if (tagName != null && tagName.equalsIgnoreCase(POLLDELAY)) {
188                                tag = MetaTag.ENUM_POLLDELAY;
189                                isMetaTag = true;
190                            } else if (tagName != null
191                                    && tagName.equalsIgnoreCase(MOVINGAVGWINDOW)) {
192                                tag = MetaTag.ENUM_MOVINGAVGWINDOW;
193                                isMetaTag = true;
194                            }
195                            if (isMetaTag) {
196                                ret = processMetaTag(tagName, tag);
197                            } else {
198                                ret = processStartElement(tagName);
199                            }
200                            if (!ret) {
201                                if (mInputStream != null) mInputStream.close();
202                                return false;
203                            }
204                            break;
205                        case XmlPullParser.END_TAG:
206                            processEndElement(mParser.getName());
207                            break;
208                    }
209                    mEventType = mParser.next();
210                }
211            } catch (XmlPullParserException xppe) {
212                Log.i(TAG, "XmlPullParserException caught in parse():" + xppe.getMessage());
213                ret = false;
214            } catch (IOException e) {
215                Log.i(TAG, "IOException caught in parse():" + e.getMessage());
216                ret = false;
217            } finally {
218                try {
219                    // end of parsing, close the stream
220                    // close is moved here, since if there is an exception
221                    // while parsing doc, input stream needs to be closed
222                    if (mInputStream != null) mInputStream.close();
223                } catch (IOException e) {
224                    Log.i(TAG, "IOException caught in parse() function");
225                    ret = false;
226                }
227                return ret;
228            }
229        }
230
231        boolean processMetaTag(String tagName, MetaTag tagId) {
232            if (mParser == null || tagName == null || mCurrZone == null)  return false;
233            ArrayList<Integer> tempList;
234            tempList = new ArrayList<Integer>();
235            // add the dummy value for TOFF now. update it once meta tag parsed
236            tempList.add(0);
237            try {
238                int eventType = mParser.next();
239                while (true) {
240                    if (eventType == XmlPullParser.START_TAG) {
241                        tempList.add(Integer.parseInt(mParser.nextText()));
242                    } else if (eventType == XmlPullParser.END_TAG &&
243                            mParser.getName().equalsIgnoreCase(tagName)) {
244                        break;
245                    }
246                    eventType = mParser.next();
247                }
248            } catch (XmlPullParserException xppe) {
249                Log.e(TAG, "XmlPullParserException:" + xppe.getMessage());
250                return false;
251            } catch (IOException ioe) {
252                Log.e(TAG, "IOException:" + ioe.getMessage());
253                return false;
254            }
255            // now that all state values are parse, copy the value corresponding to <normal>
256            // state to TOFF and last state to CRITICAL state.
257            // now we have reached end of meta tag add this temp list to appropriate list
258            switch(tagId) {
259                case ENUM_POLLDELAY:
260                    // add TOFF
261                    tempList.set(0, tempList.get(1));
262                    // add TCRITICAL
263                    tempList.add(tempList.get(tempList.size() - 1));
264                    mCurrZone.setPollDelay(tempList);
265                    break;
266                case ENUM_ZONETHRESHOLD:
267                    // add TCRITICAL
268                    tempList.add(tempList.get(tempList.size() - 1));
269                    mCurrZone.updateMaxStates(tempList.size());
270                    mCurrZone.setZoneTempThreshold(tempList);
271                    break;
272                case ENUM_MOVINGAVGWINDOW:
273                    // add TOFF
274                    tempList.set(0, tempList.get(1));
275                    // add TCRITICAL
276                    tempList.add(tempList.get(tempList.size() - 1));
277                    mCurrZone.setMovingAvgWindow(tempList);
278                    break;
279                case ENUM_UNKNOWN:
280                default:
281                    break;
282            }
283            tempList = null;
284            return true;
285        }
286
287        boolean processStartElement(String name) {
288            if (name == null)
289                return false;
290            String zoneName;
291            boolean ret = true;
292            try {
293                if (name.equalsIgnoreCase(PINFO)) {
294                    mPlatformInfo = new ThermalManager.PlatformInfo();
295                    // Default Thermal States
296                    mPlatformInfo.mMaxThermalStates = 5;
297                } else if (name.equalsIgnoreCase(PROFILE)) {
298                    mNumProfiles++;
299                } else if (name.equalsIgnoreCase(SENSOR)) {
300                    if (mCurrSensor == null) {
301                        mCurrSensor = new ThermalSensor();
302                    }
303                } else if (name.equalsIgnoreCase(SENSOR_ATTRIB)) {
304                    if (mCurrSensorAttribList == null) {
305                        mCurrSensorAttribList = new ArrayList<ThermalSensorAttrib>();
306                    }
307                    mCurrSensorAttrib = new ThermalSensorAttrib();
308                } else if (name.equalsIgnoreCase(ZONE)) {
309                    if (mThermalZones == null)
310                        mThermalZones = new ArrayList<ThermalZone>();
311                } else {
312                    // Retrieve Platform Information
313                    if (mPlatformInfo != null && name.equalsIgnoreCase("PlatformThermalStates")) {
314                        mPlatformInfo.mMaxThermalStates = Integer.parseInt(mParser.nextText());
315                        // Retrieve Zone Information
316                    } else if (name.equalsIgnoreCase("ZoneName") && mTempZoneId != -1) {
317                        mTempZoneName = mParser.nextText();
318                    } else if (name.equalsIgnoreCase("Name")) {
319                        mCurProfileName = mParser.nextText();
320                    } else if (name.equalsIgnoreCase(ZONELOGIC) && mTempZoneId != -1
321                            && mTempZoneName != null) {
322                        String zoneLogic = mParser.nextText();
323                        if (zoneLogic.equalsIgnoreCase("VirtualSkin")) {
324                            mCurrZone = new VirtualThermalZone();
325                        } else {
326                            // default zone raw
327                            mCurrZone = new RawThermalZone();
328                        }
329                        if (mCurrZone != null) {
330                            mCurrZone.setZoneName(mTempZoneName);
331                            mCurrZone.setZoneId(mTempZoneId);
332                            mCurrZone.setZoneLogic(zoneLogic);
333                        }
334                    } else if (name.equalsIgnoreCase("ZoneID")) {
335                        mTempZoneId = Integer.parseInt(mParser.nextText());
336                    } else if (name.equalsIgnoreCase("SupportsUEvent") && mCurrZone != null)
337                        mCurrZone.setSupportsUEvent(Integer.parseInt(mParser.nextText()));
338                    else if (name.equalsIgnoreCase("SupportsEmulTemp") && mCurrZone != null)
339                        mCurrZone.setEmulTempFlag(Integer.parseInt(mParser.nextText()));
340                    else if (name.equalsIgnoreCase("DebounceInterval") && mCurrZone != null)
341                        mCurrZone.setDBInterval(Integer.parseInt(mParser.nextText()));
342                    else if (name.equalsIgnoreCase(POLLDELAY) && mCurrZone != null) {
343                        mPollDelayList = new ArrayList<Integer>();
344                    } else if (name.equalsIgnoreCase(OFFSET) && mCurrZone != null) {
345                        mCurrZone.setOffset(Integer.parseInt(mParser.nextText()));
346                    }
347
348                    // Retrieve Sensor Information
349                    else if (name.equalsIgnoreCase("SensorName")) {
350                        if (mCurrSensorAttrib != null) {
351                            mCurrSensorAttrib.setSensorName(mParser.nextText());
352                        } else if (mCurrSensor != null) {
353                            mCurrSensor.setSensorName(mParser.nextText());
354                        }
355                    } else if (name.equalsIgnoreCase("SensorPath") && mCurrSensor != null)
356                        mCurrSensor.setSensorPath(mParser.nextText());
357                    else if (name.equalsIgnoreCase("InputTemp") && mCurrSensor != null)
358                        mCurrSensor.setInputTempPath(mParser.nextText());
359                    else if (name.equalsIgnoreCase("HighTemp") && mCurrSensor != null)
360                        mCurrSensor.setHighTempPath(mParser.nextText());
361                    else if (name.equalsIgnoreCase("LowTemp") && mCurrSensor != null)
362                        mCurrSensor.setLowTempPath(mParser.nextText());
363                    else if (name.equalsIgnoreCase("UEventDevPath") && mCurrSensor != null)
364                        mCurrSensor.setUEventDevPath(mParser.nextText());
365                    else if (name.equalsIgnoreCase("ErrorCorrection") && mCurrSensor != null)
366                        mCurrSensor.setErrorCorrectionTemp(Integer.parseInt(mParser.nextText()));
367                    else if (name.equalsIgnoreCase(WEIGHT) && mCurrSensorAttrib != null) {
368                        if (mWeightList == null) {
369                            mWeightList = new ArrayList<Integer>();
370                        }
371                        if (mWeightList != null) {
372                            mWeightList.add(Integer.parseInt(mParser.nextText()));
373                        }
374                    } else if (name.equalsIgnoreCase(ORDER) && mCurrSensorAttrib != null) {
375                        if (mOrderList == null) {
376                            mOrderList = new ArrayList<Integer>();
377                        }
378                        if (mOrderList != null) {
379                            mOrderList.add(Integer.parseInt(mParser.nextText()));
380                        }
381                    }
382                }
383            } catch (XmlPullParserException e) {
384                Log.i(TAG, "XmlPullParserException caught in processStartElement()");
385                ret = false;
386            } catch (IOException e) {
387                Log.i(TAG, "IOException caught in processStartElement()");
388                ret = false;
389            } finally {
390                return ret;
391            }
392        }
393
394        void processEndElement(String name) {
395            if (name.equalsIgnoreCase(SENSOR)) {
396                // insert in map, only if no sensor with same name already in map
397                if (mCurrSensor == null) return;
398                mCurrSensor.setAutoValues();
399                if (ThermalManager.getSensor(mCurrSensor.getSensorName()) == null) {
400                    ThermalManager.sSensorMap.put(mCurrSensor.getSensorName(), mCurrSensor);
401                } else {
402                    Log.i(TAG, "sensor:" + mCurrSensor.getSensorName() + " already present");
403                }
404                mCurrSensor = null;
405            } else if (name.equalsIgnoreCase(SENSOR_ATTRIB) && mCurrSensorAttribList != null) {
406                if (mCurrSensorAttrib != null) {
407                    mCurrSensorAttrib.setWeights(mWeightList);
408                    mCurrSensorAttrib.setOrder(mOrderList);
409                }
410                mWeightList = null;
411                mOrderList = null;
412                if (mCurrSensorAttrib != null
413                        && ThermalManager.getSensor(mCurrSensorAttrib.getSensorName()) != null) {
414                    // this is valid sensor, so now update the zone sensorattrib list
415                    // and sensor list.This check is needed to avoid a scenario where
416                    // a invalid sensor name might be included in sensorattrib list.
417                    // This check filters out all invalid sensor attrib.
418                    mCurrSensorAttribList.add(mCurrSensorAttrib);
419                }
420            } else if (name.equalsIgnoreCase(ZONE) && mCurrZone != null
421                    && mThermalZones != null) {
422                mCurrZone.setSensorList(mCurrSensorAttribList);
423                mThermalZones.add(mCurrZone);
424                mCurrZone = null;
425                mTempZoneId = -1;
426                mTempZoneName = null;
427                mCurrSensorAttribList = null;
428            } else if (name.equalsIgnoreCase(POLLDELAY) && mCurrZone != null) {
429                mCurrZone.setPollDelay(mPollDelayList);
430                mPollDelayList = null;
431            } else if (name.equalsIgnoreCase(MOVINGAVGWINDOW) && mCurrZone != null) {
432                mCurrZone.setMovingAvgWindow(mMovingAvgWindowList);
433                mMovingAvgWindowList = null;
434            } else if (name.equalsIgnoreCase(THERMAL_CONFIG)) {
435                // This indicates we have not seen any <Profile> tag.
436                // Consider it as if we have only one 'Default' Profile.
437                if (mNumProfiles == 0) {
438                    ThermalManager.sProfileZoneMap.put(mCurProfileName, mThermalZones);
439                }
440                mDone = true;
441            } else if (name.equalsIgnoreCase(PROFILE)) {
442                ThermalManager.sProfileZoneMap.put(mCurProfileName, mThermalZones);
443                mThermalZones = null;
444            } else if (name.equalsIgnoreCase(ZONETHRESHOLD) && mCurrZone != null) {
445                mCurrZone.setZoneTempThreshold(mZoneThresholdList);
446                mZoneThresholdList = null;
447            }
448        }
449    }
450
451    /* Class to notifying thermal events */
452    public class Notify implements Runnable {
453        private final BlockingQueue cQueue;
454        Notify (BlockingQueue q) {
455            cQueue = q;
456        }
457
458        public void run () {
459            try {
460                while (true) { consume((ThermalEvent) cQueue.take()); }
461            } catch (InterruptedException ex) {
462                Log.i(TAG, "caught InterruptedException in run()");
463            }
464        }
465
466        /* Method to consume thermal event */
467        public void consume (ThermalEvent event) {
468            Intent statusIntent = new Intent();
469            statusIntent.setAction(ThermalManager.ACTION_THERMAL_ZONE_STATE_CHANGED);
470
471            statusIntent.putExtra(ThermalManager.EXTRA_NAME, event.mZoneName);
472            statusIntent.putExtra(ThermalManager.EXTRA_PROFILE, event.mProfName);
473            statusIntent.putExtra(ThermalManager.EXTRA_ZONE, event.mZoneId);
474            statusIntent.putExtra(ThermalManager.EXTRA_EVENT, event.mEventType);
475            statusIntent.putExtra(ThermalManager.EXTRA_STATE, event.mThermalLevel);
476            statusIntent.putExtra(ThermalManager.EXTRA_TEMP, event.mZoneTemp);
477
478            /* Send the Thermal Intent */
479            mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
480        }
481    }
482
483    /* Register for boot complete Intent */
484    public ThermalService() {
485        super();
486    }
487
488    private void configureTurboProperties() {
489        String prop = SystemProperties.get("persist.thermal.turbo.dynamic");
490
491        if (prop.equals("0")) {
492            ThermalManager.sIsDynamicTurboEnabled = false;
493            Log.i(TAG, "Dynamic Turbo disabled through persist.thermal.turbo.dynamic");
494        } else if (prop.equals("1")) {
495            ThermalManager.sIsDynamicTurboEnabled = true;
496            Log.i(TAG, "Dynamic Turbo enabled through persist.thermal.turbo.dynamic");
497        } else {
498            // Set it to true so that we don't write ThermalManager.DISABLE_DYNAMIC_TURBO
499            // into any cooling device based on this.
500            ThermalManager.sIsDynamicTurboEnabled = true;
501            Log.i(TAG, "property persist.thermal.turbo.dynamic not present");
502        }
503    }
504
505    @Override
506    public void onDestroy() {
507        // stop all thread
508        ThermalManager.stopCurrentProfile();
509        ThermalManager.sCoolingManager.unregisterReceivers();
510        // clear all static data
511        ThermalManager.clearData();
512        Log.w(TAG, "ituxd destroyed");
513    }
514
515    @Override
516    public void onCreate() {
517        mContext = getApplicationContext();
518        ThermalManager.setContext(mContext);
519    }
520
521    @Override
522    public IBinder onBind(Intent intent) {
523        return(null);
524    }
525
526    @Override
527    public int onStartCommand(Intent intent, int flags, int startid)
528    {
529        boolean ret;
530        ThermalManager.loadiTUXVersion();
531        /* Check for exitence of config files */
532        ThermalUtils.initialiseConfigFiles(mContext);
533        if (!ThermalManager.sIsConfigFiles && !ThermalManager.sIsOverlays) {
534            Log.i(TAG, "Thermal config files do not exist. Exiting ThermalService");
535            return START_NOT_STICKY;
536        }
537
538        /* Set Dynamic Turbo status based on the property */
539        configureTurboProperties();
540
541        /* Intiliaze DTS TjMax temperature */
542        ThermalUtils.getTjMax();
543
544        /* Initialize the Thermal Cooling Manager */
545        ThermalManager.sCoolingManager = new ThermalCooling();
546        if (ThermalManager.sCoolingManager != null) {
547            ret = ThermalManager.sCoolingManager.init(mContext);
548            if (!ret) {
549                Log.i(TAG, "CoolingManager is null. Exiting ThermalService");
550                return START_NOT_STICKY;
551            }
552        }
553
554        /* Parse the thermal configuration file to determine zone/sensor information */
555        ThermalParser mThermalParser;
556        if (ThermalManager.sIsConfigFiles) {
557            mThermalParser = new ThermalParser(ThermalManager.sSensorFilePath);
558        } else {
559            mThermalParser = new ThermalParser();
560        }
561
562        if (mThermalParser != null) {
563            ret = mThermalParser.parse();
564            if (!ret) {
565                ThermalManager.sCoolingManager.unregisterReceivers();
566                Log.i(TAG, "thermal_sensor_config.xml parsing Failed. Exiting ThermalService");
567                return START_NOT_STICKY;
568            }
569        }
570
571        /* Retrieve the platform information after parsing */
572        ThermalManager.sPlatformInfo = mThermalParser.getPlatformInfo();
573
574        /* Print thermal_sensor_config.xml information */
575        Iterator it = ThermalManager.sProfileZoneMap.entrySet().iterator();
576        while (it.hasNext()) {
577            Map.Entry entry = (Map.Entry) it.next();
578            String key = (String) entry.getKey();
579            ArrayList<ThermalZone> tzList = (ArrayList<ThermalZone>) entry.getValue();
580            Log.i(TAG, "Zones under Profile: " + key);
581            for (ThermalZone tz : tzList) tz.printAttrs();
582        }
583
584        /* read persistent system properties for shutdown notification */
585        ThermalManager.readShutdownNotiferProperties();
586        /* initialize the thermal notifier thread */
587        Notify notifier = new Notify(ThermalManager.sEventQueue);
588        new Thread(notifier, "ThermalNotifier").start();
589
590        ThermalManager.buildProfileNameList();
591        ThermalManager.initializeStickyIntent();
592
593        /* Building bucket size for all profiles */
594        ThermalManager.setBucketSizeForProfiles();
595
596        /* Start monitoring the zones in Default Thermal Profile */
597        ThermalManager.startDefaultProfile();
598
599        return START_STICKY;
600    }
601}
602