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