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.app.IntentService;
20 import android.app.Service;
21 import android.content.BroadcastReceiver;
22 import android.content.ContentResolver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.content.pm.PackageManager;
27 import android.os.Handler;
28 import android.os.IBinder;
29 import android.os.Looper;
30 import android.os.Message;
31 import android.os.Process;
32 import android.os.SystemProperties;
33 import android.os.UserHandle;
34 import android.util.Log;
35 
36 import java.io.BufferedReader;
37 import java.io.File;
38 import java.io.FileNotFoundException;
39 import java.io.FileReader;
40 import java.io.IOException;
41 import java.lang.ClassLoader;
42 import java.lang.NullPointerException;
43 import java.lang.reflect.Array;
44 import java.lang.SecurityException;
45 import java.util.ArrayList;
46 import java.util.concurrent.BlockingQueue;
47 import java.util.concurrent.ArrayBlockingQueue;
48 import java.util.Iterator;
49 import java.util.Map;
50 
51 import org.xmlpull.v1.XmlPullParser;
52 import org.xmlpull.v1.XmlPullParserException;
53 import 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  */
66 public 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 
ThermalParser(String fname)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 
ThermalParser()149         ThermalParser() {
150             mParser = mContext.getResources().
151                     getXml(ThermalManager.sSensorFileXmlId);
152         }
153 
getPlatformInfo()154         public ThermalManager.PlatformInfo getPlatformInfo() {
155             return mPlatformInfo;
156         }
157 
parse()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 
processMetaTag(String tagName, MetaTag tagId)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 
processStartElement(String name)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 
processEndElement(String name)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;
Notify(BlockingQueue q)454         Notify (BlockingQueue q) {
455             cQueue = q;
456         }
457 
run()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 */
consume(ThermalEvent 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 */
ThermalService()484     public ThermalService() {
485         super();
486     }
487 
configureTurboProperties()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
onDestroy()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
onCreate()516     public void onCreate() {
517         mContext = getApplicationContext();
518         ThermalManager.setContext(mContext);
519     }
520 
521     @Override
onBind(Intent intent)522     public IBinder onBind(Intent intent) {
523         return(null);
524     }
525 
526     @Override
onStartCommand(Intent intent, int flags, int startid)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