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