Home | History | Annotate | Download | only in thermal
      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 org.xmlpull.v1.XmlPullParser;
     20 import org.xmlpull.v1.XmlPullParserException;
     21 import org.xmlpull.v1.XmlPullParserFactory;
     22 
     23 import android.content.BroadcastReceiver;
     24 import android.content.Context;
     25 import android.content.Intent;
     26 import android.content.IntentFilter;
     27 import android.os.SystemProperties;
     28 import android.util.Log;
     29 
     30 import java.io.FileNotFoundException;
     31 import java.io.FileReader;
     32 import java.io.IOException;
     33 import java.lang.reflect.InvocationTargetException;
     34 import java.lang.reflect.Method;
     35 import java.util.ArrayList;
     36 import java.util.Hashtable;
     37 
     38 /**
     39  * The ThermalCooling class parses the thermal_throttle_config.xml. This class
     40  * receives Thermal Intents and takes appropriate actions based on the policies
     41  * configured in the xml file.
     42  *
     43  * @hide
     44  */
     45 public class ThermalCooling {
     46     private static final String TAG = "ThermalCooling";
     47     private static final String THERMAL_SHUTDOWN_NOTIFY_PATH =
     48             "/sys/module/intel_mid_osip/parameters/force_shutdown_occured";
     49 
     50     private Context mContext;
     51 
     52     // count to keep track of zones in critical state, waiting for shutdown
     53     private int mCriticalZonesCount = 0;
     54     private static final Object sCriticalZonesCountLock = new Object();
     55 
     56     private ThermalZoneReceiver mThermalIntentReceiver = new ThermalZoneReceiver();
     57     private ProfileChangeReceiver mProfChangeReceiver = new ProfileChangeReceiver();
     58     private boolean mProfChangeListenerInitialized = false;
     59     /**
     60      * This is the parser class which parses the thermal_throttle_config.xml
     61      * file.
     62      */
     63     protected enum MetaTag {
     64         ENUM_THROTTLEVALUES,
     65         ENUM_THROTTLEMASK,
     66         ENUM_DETHROTTLEMASK,
     67         ENUM_UNKNOWN
     68     }
     69 
     70     public class ThermalParser {
     71         private static final String THERMAL_THROTTLE_CONFIG = "thermalthrottleconfig";
     72 
     73         private static final String CDEVINFO = "ContributingDeviceInfo";
     74 
     75         private static final String ZONETHROTINFO = "ZoneThrottleInfo";
     76 
     77         private static final String COOLINGDEVICEINFO = "CoolingDeviceInfo";
     78 
     79         private static final String THROTTLEMASK = "ThrottleDeviceMask";
     80 
     81         private static final String DETHROTTLEMASK = "DethrottleDeviceMask";
     82 
     83         private static final String THROTTLEVALUES = "ThrottleValues";
     84 
     85         private static final String COOLINGDEVICESTATES = "CoolingDeviceStates";
     86 
     87         private static final String PROFILE = "Profile";
     88 
     89         private ArrayList<Integer> mTempMaskList;
     90 
     91         private ArrayList<Integer> mTempThrottleValuesList;;
     92 
     93         private boolean done = false;
     94 
     95         XmlPullParserFactory mFactory;
     96 
     97         XmlPullParser mParser;
     98 
     99         ThermalCoolingDevice mDevice = null;
    100 
    101         /* Hashtable of (ZoneID and ZoneCoolerBindingInfo object) */
    102         Hashtable<Integer, ThermalManager.ZoneCoolerBindingInfo> mZoneCoolerBindMap = null;
    103         String mCurProfileName = ThermalManager.DEFAULT_PROFILE_NAME;
    104         int mNumProfiles = 0;
    105 
    106         ThermalManager.ZoneCoolerBindingInfo mZone = null;
    107 
    108         FileReader mInputStream = null;
    109 
    110         ThermalParser(String fname) {
    111             try {
    112                 mFactory = XmlPullParserFactory.newInstance(
    113                         System.getProperty(XmlPullParserFactory.PROPERTY_NAME), null);
    114                 mFactory.setNamespaceAware(true);
    115                 mParser = mFactory.newPullParser();
    116             } catch (XmlPullParserException xppe) {
    117                 Log.e(TAG, "mParser NewInstance Exception");
    118             }
    119 
    120             try {
    121                 mInputStream = new FileReader(fname);
    122                 if (mInputStream == null)
    123                     return;
    124                 if (mParser != null) {
    125                     mParser.setInput(mInputStream);
    126                 }
    127                 mDevice = null;
    128                 mZone = null;
    129             } catch (XmlPullParserException xppe) {
    130                 Log.e(TAG, "mParser setInput XmlPullParserException");
    131             } catch (FileNotFoundException e) {
    132                 Log.e(TAG, "mParser setInput FileNotFoundException");
    133             }
    134 
    135         }
    136 
    137         ThermalParser() {
    138             mParser = mContext.getResources().
    139                     getXml(ThermalManager.sThrottleFileXmlId);
    140         }
    141 
    142         public boolean parse() {
    143             if (ThermalManager.sIsOverlays == false && mInputStream == null) return false;
    144             /* if mParser is null, close any open stream before exiting */
    145             if (mParser == null) {
    146                 try {
    147                     if (mInputStream != null) {
    148                         mInputStream.close();
    149                     }
    150                 } catch (IOException e) {
    151                     Log.i(TAG, "IOException caught in parse() function");
    152                 }
    153                 return false;
    154             }
    155 
    156             boolean ret = true;
    157             MetaTag tag = MetaTag.ENUM_UNKNOWN;
    158             try {
    159                 int mEventType = mParser.getEventType();
    160                 while (mEventType != XmlPullParser.END_DOCUMENT && !done) {
    161                     switch (mEventType) {
    162                         case XmlPullParser.START_DOCUMENT:
    163                             Log.i(TAG, "StartDocument");
    164                             break;
    165                         case XmlPullParser.START_TAG:
    166                             String tagName = mParser.getName();
    167                             boolean isMetaTag = false;
    168                             if (tagName != null && tagName.equalsIgnoreCase(THROTTLEVALUES)) {
    169                                 tag = MetaTag.ENUM_THROTTLEVALUES;
    170                                 isMetaTag = true;
    171                             } else if (tagName != null && tagName.equalsIgnoreCase(THROTTLEMASK)) {
    172                                 tag = MetaTag.ENUM_THROTTLEMASK;
    173                                 isMetaTag = true;
    174                             } else if (tagName != null
    175                                     && tagName.equalsIgnoreCase(DETHROTTLEMASK)) {
    176                                 tag = MetaTag.ENUM_DETHROTTLEMASK;
    177                                 isMetaTag = true;
    178                             }
    179                             if (isMetaTag) {
    180                                 ret = processMetaTag(tagName, tag);
    181                             } else {
    182                                 ret = processStartElement(tagName);
    183                             }
    184                             if (!ret) {
    185                                 if (mInputStream != null) mInputStream.close();
    186                                 return false;
    187                             }
    188                             break;
    189                         case XmlPullParser.END_TAG:
    190                             processEndElement(mParser.getName());
    191                             break;
    192                     }
    193                     mEventType = mParser.next();
    194                 }
    195             } catch (XmlPullParserException xppe) {
    196                 Log.i(TAG, "XmlPullParserException caught in parse():" + xppe.getMessage());
    197                 ret = false;
    198             } catch (IOException e) {
    199                 Log.i(TAG, "IOException caught in parse():" + e.getMessage());
    200                 ret = false;
    201             } finally {
    202                 try {
    203                     // end of parsing, close the stream
    204                     // close is moved here, since if there is an exception
    205                     // while parsing doc, input stream needs to be closed
    206                     if (mInputStream != null) {
    207                         mInputStream.close();
    208                     }
    209                 } catch (IOException e) {
    210                     Log.i(TAG, "IOException caught in parse() function");
    211                     ret = false;
    212                 }
    213                 return ret;
    214             }
    215         }
    216 
    217         public boolean processMetaTag(String tagName, MetaTag tagId) {
    218             if (mParser == null || tagName == null)  return false;
    219             ArrayList<Integer> tempList = new ArrayList<Integer>();
    220             try {
    221                 int eventType = mParser.next();
    222                 while (true) {
    223                     if (eventType == XmlPullParser.START_TAG) {
    224                         tempList.add(Integer.parseInt(mParser.nextText()));
    225                     } else if (eventType == XmlPullParser.END_TAG &&
    226                             mParser.getName().equalsIgnoreCase(tagName)) {
    227                         break;
    228                     }
    229                     eventType = mParser.next();
    230                 }
    231             } catch (XmlPullParserException xppe) {
    232                 Log.e(TAG, "XmlPullParserException:" + xppe.getMessage());
    233                 return false;
    234             } catch (IOException ioe) {
    235                 Log.e(TAG, "IOException:" + ioe.getMessage());
    236                 return false;
    237             }
    238 
    239             switch(tagId) {
    240                 case ENUM_THROTTLEVALUES:
    241                     if (mDevice == null) {
    242                         return false;
    243                     } else {
    244                         // add throttle value for TCRITICAL (same as last value)
    245                         tempList.add(tempList.get(tempList.size() - 1));
    246                         mDevice.setThrottleValuesList(tempList);
    247                     }
    248                     break;
    249                 case ENUM_THROTTLEMASK:
    250                     if (mZone == null || mZone.getLastCoolingDeviceInstance() ==  null) {
    251                         return false;
    252                     } else {
    253                         // Always throttle at CRITICAL state (last state)
    254                         tempList.add(1);
    255                         mZone.getLastCoolingDeviceInstance().setThrottleMaskList(tempList);
    256                     }
    257                     break;
    258                 case ENUM_DETHROTTLEMASK:
    259                     if (mZone == null || mZone.getLastCoolingDeviceInstance() ==  null) {
    260                         return false;
    261                     } else {
    262                         // Dethrottling at CRITICAL state (last state) is dontcare condition
    263                         tempList.add(0);
    264                         mZone.getLastCoolingDeviceInstance().setDeThrottleMaskList(tempList);
    265                     }
    266                     break;
    267                 default:
    268                     return false;
    269             }
    270             return true;
    271         }
    272         boolean processStartElement(String name) {
    273             if (name == null)
    274                 return false;
    275             boolean ret = true;
    276             try {
    277                 if (name.equalsIgnoreCase(CDEVINFO)) {
    278                     if (mDevice == null)
    279                         mDevice = new ThermalCoolingDevice();
    280                 } else if (name.equalsIgnoreCase(ZONETHROTINFO)) {
    281                     if (mZone == null) {
    282                         mZone = new ThermalManager.ZoneCoolerBindingInfo();
    283                     }
    284                     if (mZoneCoolerBindMap == null) {
    285                         mZoneCoolerBindMap = new Hashtable<Integer,
    286                                 ThermalManager.ZoneCoolerBindingInfo>();
    287                     }
    288                 } else if (name.equalsIgnoreCase(PROFILE)) {
    289                     mNumProfiles++;
    290                     if (mZoneCoolerBindMap == null) {
    291                         mZoneCoolerBindMap = new Hashtable<Integer,
    292                                 ThermalManager.ZoneCoolerBindingInfo>();
    293                     }
    294                 } else if (name.equalsIgnoreCase(COOLINGDEVICEINFO) && mZone != null) {
    295                     if (mZone.getCoolingDeviceInfoList() == null) {
    296                         mZone.initializeCoolingDeviceInfoList();
    297                     }
    298                     mZone.createNewCoolingDeviceInstance();
    299                 } else {
    300                     // Retrieve zone and cooling device mapping
    301                     if (name.equalsIgnoreCase("ZoneID") && mZone != null) {
    302                         mZone.setZoneID(Integer.parseInt(mParser.nextText()));
    303                     } else if (name.equalsIgnoreCase("CriticalShutDown") && mZone != null) {
    304                         mZone.setCriticalActionShutdown(Integer.parseInt(mParser.nextText()));
    305                     } else if (name.equalsIgnoreCase(THROTTLEMASK) && mZone != null) {
    306                         mTempMaskList = new ArrayList<Integer>();
    307                     } else if (name.equalsIgnoreCase(DETHROTTLEMASK) && mZone != null) {
    308                         mTempMaskList = new ArrayList<Integer>();
    309                     } else if (name.equalsIgnoreCase("CoolingDevId") && mZone != null) {
    310                         mZone.getLastCoolingDeviceInstance().setCoolingDeviceId(
    311                                 Integer.parseInt(mParser.nextText()));
    312                     } else if (name.equalsIgnoreCase(COOLINGDEVICESTATES) && mZone != null) {
    313                         // Increase cooling device states by 1, required for CRITICAL state
    314                         mZone.getLastCoolingDeviceInstance().setCoolingDeviceStates(
    315                                 Integer.parseInt(mParser.nextText()) + 1);
    316                     }
    317                     // Retrieve cooling device information
    318                     if (name.equalsIgnoreCase("CDeviceName") && mDevice != null) {
    319                         mDevice.setDeviceName(mParser.nextText());
    320                     } else if (name.equalsIgnoreCase("CDeviceID") && mDevice != null) {
    321                         mDevice.setDeviceId(Integer.parseInt(mParser.nextText()));
    322                     } else if (name.equalsIgnoreCase("CDeviceClassPath") && mDevice != null) {
    323                         mDevice.setClassPath(mParser.nextText());
    324                     } else if (name.equalsIgnoreCase("CDeviceThrottlePath") && mDevice != null) {
    325                         mDevice.setThrottlePath(mParser.nextText());
    326                     } else if (name.equalsIgnoreCase("Name")) {
    327                         mCurProfileName = mParser.nextText();
    328                     }
    329                 }
    330             } catch (XmlPullParserException e) {
    331                 Log.i(TAG, "XmlPullParserException caught in processStartElement()");
    332                 ret = false;
    333             } catch (IOException e) {
    334                 Log.i(TAG, "IOException caught in processStartElement()");
    335                 ret = false;
    336             } finally {
    337                 return ret;
    338             }
    339         }
    340 
    341         void processEndElement(String name) {
    342             if (name == null)
    343                 return;
    344             if (name.equalsIgnoreCase(CDEVINFO) && mDevice != null) {
    345                 // if cooling dev suports less then DEFAULT throttle values donot add to map.
    346                 if (mDevice.getNumThrottleValues() < ThermalManager.DEFAULT_NUM_THROTTLE_VALUES) {
    347                     Log.i(TAG, "cooling dev:" + mDevice.getDeviceName()
    348                             + " deactivated! throttle values < "
    349                             + ThermalManager.DEFAULT_NUM_THROTTLE_VALUES);
    350                     mDevice = null;
    351                     return;
    352                 }
    353                 if (mDevice.getThrottlePath().equals("auto")) {
    354                     mDevice.setThrottlePath("auto");
    355                 }
    356                 if (loadCoolingDevice(mDevice)) {
    357                     ThermalManager.sCDevMap.put(mDevice.getDeviceId(), mDevice);
    358                 }
    359                 mDevice = null;
    360             } else if (name.equalsIgnoreCase(ZONETHROTINFO) && mZone != null) {
    361                 mZone.printAttributes();
    362                 if (mZoneCoolerBindMap != null) {
    363                     mZoneCoolerBindMap.put(mZone.getZoneID(), mZone);
    364                 }
    365                 mZone = null;
    366             } else if (name.equalsIgnoreCase(PROFILE)) {
    367                 if (mZoneCoolerBindMap != null) {
    368                     ThermalManager.sProfileBindMap.put(mCurProfileName, mZoneCoolerBindMap);
    369                     mZoneCoolerBindMap = new Hashtable<Integer,
    370                             ThermalManager.ZoneCoolerBindingInfo>();
    371                 }
    372             } else if (name.equalsIgnoreCase(THERMAL_THROTTLE_CONFIG)) {
    373                 Log.i(TAG, "Parsing Finished..");
    374                 // This indicates we have not seen any <Profile> tag.
    375                 // Consider it as if we have only one 'Default' Profile.
    376                 if (mNumProfiles == 0 && mZoneCoolerBindMap != null) {
    377                     ThermalManager.sProfileBindMap.put(mCurProfileName, mZoneCoolerBindMap);
    378                 }
    379                 done = true;
    380             } else if (name.equalsIgnoreCase(COOLINGDEVICEINFO) && mZone != null) {
    381                 ThermalManager.ZoneCoolerBindingInfo.CoolingDeviceInfo cDevInfo;
    382                 cDevInfo = mZone.getLastCoolingDeviceInstance();
    383                 if (cDevInfo != null) {
    384                     ThermalCoolingDevice cDev = ThermalManager.sCDevMap
    385                             .get(cDevInfo.getCoolingDeviceId());
    386                     if (cDev == null) return;
    387                     int cds = cDevInfo.getCoolingDeviceStates();
    388                     // check the CDS against the number of throttle values exposed.
    389                     // If exceeds, cap it.
    390                     if (cds > cDev.getNumThrottleValues()) {
    391                         cDevInfo.setCoolingDeviceStates(cDev.getNumThrottleValues());
    392                         Log.i(TAG, "capping cdevid: " + cDevInfo.getCoolingDeviceId()
    393                                 + " to " + cDev.getNumThrottleValues() + " states");
    394                     }
    395                     if (cDevInfo.checkMaskList(cDev.getNumThrottleValues())) {
    396                         // add only active cooling devices to list
    397                         mZone.addCoolingDeviceToList(cDevInfo);
    398                     }
    399                 }
    400             }
    401         }
    402     }
    403 
    404     private void configureDynamicTurbo() {
    405         // Disable Dynamic Turbo based on the system property
    406         int indx = ThermalUtils.getCoolingDeviceIndexContains("SoC");
    407         if (indx != -1 && !ThermalManager.sIsDynamicTurboEnabled) {
    408             String path = ThermalManager.sCoolingDeviceBasePath + indx
    409                     + ThermalManager.sCoolingDeviceState;
    410             ThermalUtils.writeSysfs(path, ThermalManager.DISABLE_DYNAMIC_TURBO);
    411         }
    412     }
    413 
    414     public boolean init(Context context) {
    415         Log.i(TAG, "Thermal Cooling manager init() called");
    416 
    417         mContext = context;
    418         ThermalParser parser;
    419         if (!ThermalManager.sIsOverlays) {
    420             parser = new ThermalParser(ThermalManager.sThrottleFilePath);
    421         } else {
    422             parser = new ThermalParser();
    423         }
    424 
    425         if (parser == null || !parser.parse()) {
    426             Log.i(TAG, "thermal_throttle_config.xml parsing failed");
    427             return false;
    428         }
    429 
    430         // Set this sZoneCoolerBindMap to the DefaultProfile Map
    431         ThermalManager.setCurBindMap(ThermalManager.DEFAULT_PROFILE_NAME);
    432 
    433         // Register for thermal zone state changed notifications
    434         IntentFilter filter = new IntentFilter();
    435         filter.addAction(ThermalManager.ACTION_THERMAL_ZONE_STATE_CHANGED);
    436         mContext.registerReceiver(mThermalIntentReceiver, filter);
    437 
    438         configureDynamicTurbo();
    439         return true;
    440     }
    441 
    442     private final class ProfileChangeReceiver extends BroadcastReceiver {
    443         @Override
    444         public void onReceive(Context context, Intent intent) {
    445             String action = intent.getAction();
    446             if (action.equals(ThermalManager.ACTION_CHANGE_THERMAL_PROFILE)) {
    447                 String profName = intent.getStringExtra(ThermalManager.EXTRA_PROFILE);
    448                 if (profName != null) {
    449                     ThermalManager.changeThermalProfile(profName);
    450                 }
    451             }
    452         }
    453     }
    454 
    455     private void incrementCrticalZoneCount() {
    456         synchronized(sCriticalZonesCountLock) {
    457             mCriticalZonesCount++;
    458         }
    459     }
    460 
    461     private final class ThermalZoneReceiver extends BroadcastReceiver {
    462         @Override
    463         public void onReceive(Context context, Intent intent) {
    464             String zoneName = intent.getStringExtra(ThermalManager.EXTRA_NAME);
    465             String profName = intent.getStringExtra(ThermalManager.EXTRA_PROFILE);
    466             int thermZone = intent.getIntExtra(ThermalManager.EXTRA_ZONE, -1);
    467             int thermState = intent.getIntExtra(ThermalManager.EXTRA_STATE, 0);
    468             int thermEvent = intent.getIntExtra(ThermalManager.EXTRA_EVENT, 0);
    469             int zoneTemp = intent.getIntExtra(ThermalManager.EXTRA_TEMP, 0);
    470 
    471             // Assume 'Default' profile if there is no profile parameter
    472             // as part of the intent.
    473             if (profName == null) {
    474                 profName = ThermalManager.DEFAULT_PROFILE_NAME;
    475             }
    476 
    477             Log.i(TAG, "Received THERMAL INTENT:(ProfileName, ZoneName, State, EventType, Temp):"
    478                     + "(" + profName + ", " + zoneName + ", " + thermState + ", "
    479                     + ThermalZone.getEventTypeAsString(thermEvent) + ", " + zoneTemp + ")");
    480 
    481             Hashtable<Integer, ThermalManager.ZoneCoolerBindingInfo> mBindMap =
    482                     ThermalManager.getBindMap(profName);
    483             if (mBindMap == null) {
    484                 Log.i(TAG, "mBindMap null inside ThermalZoneReceiver");
    485                 return;
    486             }
    487 
    488             ThermalManager.ZoneCoolerBindingInfo zoneCoolerBindInfo = mBindMap.get(thermZone);
    489             if (zoneCoolerBindInfo == null) {
    490                 Log.i(TAG, "zoneCoolerBindInfo null for zoneID" + thermZone);
    491                 return;
    492             }
    493 
    494             boolean flag = zoneCoolerBindInfo.getCriticalActionShutdown() == 1;
    495             int lastState = zoneCoolerBindInfo.getLastState();
    496             if (thermState < lastState) {
    497                 ThermalManager.updateZoneCriticalPendingMap(thermZone,
    498                         ThermalManager.CRITICAL_FALSE);
    499             } else if (thermState == lastState && flag) {
    500                 /* no telephony support, so (!isEmergencyCallOnGoing) is true */
    501                 if (true) {
    502                     doShutdown();
    503                 } else {
    504                     // increment the count of zones in critical state pending on shutdown
    505                     ThermalManager.updateZoneCriticalPendingMap(thermZone,
    506                             ThermalManager.CRITICAL_TRUE);
    507                 }
    508             }
    509 
    510             /* if THERMALOFF is the zone state, it is guaranteed that the zone has transitioned
    511             from a higher state, due to a low event, to THERMALOFF.Hence take de-throttling action
    512             corresponding to NORMAL */
    513             if (thermState == ThermalManager.THERMAL_STATE_OFF) {
    514                 thermState = ThermalManager.THERMAL_STATE_NORMAL;
    515             }
    516             handleThermalEvent(thermZone, thermEvent, thermState, zoneCoolerBindInfo);
    517         }
    518     }
    519 
    520     private boolean loadCoolingDevice(ThermalCoolingDevice device) {
    521         Class cls;
    522         Method throttleMethod;
    523         String classPath = device.getClassPath();
    524 
    525         if (classPath == null) {
    526             Log.i(TAG, "ClassPath not found");
    527             return false;
    528         }
    529 
    530         if (classPath.equalsIgnoreCase("none") || classPath.equalsIgnoreCase("auto")
    531                 || classPath.equalsIgnoreCase("AppAgent")) {
    532             Log.i(TAG, "ClassPath: none/auto/AppAgent");
    533             return true;
    534         }
    535 
    536         /* Load the cooling device class */
    537         try {
    538             cls = Class.forName(classPath);
    539             device.setDeviceClass(cls);
    540         } catch (Throwable e) {
    541             Log.i(TAG, "Unable to load class " + classPath);
    542             return false;
    543         }
    544 
    545         /* Initialize the cooling device class */
    546         try {
    547             Class partypes[] = new Class[3];
    548             partypes[0] = Context.class;
    549             partypes[1] = String.class;
    550             partypes[2] = ArrayList.class;
    551             Method init = cls.getMethod("init", partypes);
    552             Object arglist[] = new Object[3];
    553             arglist[0] = mContext;
    554             arglist[1] = device.getThrottlePath();
    555             arglist[2] = device.getThrottleValuesList();
    556             init.invoke(cls, arglist);
    557         } catch (NoSuchMethodException e) {
    558             Log.i(TAG, "NoSuchMethodException caught in device class init: " + classPath);
    559         } catch (SecurityException e) {
    560             Log.i(TAG, "SecurityException caught in device class init: " + classPath);
    561         } catch (IllegalAccessException e) {
    562             Log.i(TAG, "IllegalAccessException caught in device class init: " + classPath);
    563         } catch (IllegalArgumentException e) {
    564             Log.i(TAG, "IllegalArgumentException caught in device class init: " + classPath);
    565         } catch (ExceptionInInitializerError e) {
    566             Log.i(TAG, "ExceptionInInitializerError caught in device class init: " + classPath);
    567         } catch (InvocationTargetException e) {
    568             Log.i(TAG, "InvocationTargetException caught in device class init: " + classPath);
    569         }
    570 
    571         /* Get the throttleDevice method from cooling device class */
    572         try {
    573             Class partypes[] = new Class[1];
    574             partypes[0] = Integer.TYPE;
    575             throttleMethod = cls.getMethod("throttleDevice", partypes);
    576             device.setThrottleMethod(throttleMethod);
    577         } catch (NoSuchMethodException e) {
    578             Log.i(TAG, "NoSuchMethodException caught initializing throttle function");
    579         } catch (SecurityException e) {
    580             Log.i(TAG, "SecurityException caught initializing throttle function");
    581         }
    582 
    583         return true;
    584     }
    585 
    586 
    587     public void doShutdown() {
    588         ThermalUtils.writeSysfs(THERMAL_SHUTDOWN_NOTIFY_PATH, 1);
    589         /* We must avoid reboot after shutdown. */
    590         SystemProperties.set("sys.property_forcedshutdown", "1");
    591         Intent criticalIntent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
    592         criticalIntent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
    593         criticalIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    594         Log.i(TAG, "Thermal Service initiating shutdown");
    595         mContext.startActivity(criticalIntent);
    596     }
    597 
    598     public void registerProfChangeListener() {
    599         IntentFilter profChangeIntentFilter = new IntentFilter();
    600         profChangeIntentFilter.addAction(ThermalManager.ACTION_CHANGE_THERMAL_PROFILE);
    601         // TODO: add some permission (BRICK ??) to protect it from third party apps
    602         mContext.registerReceiver(mProfChangeReceiver, profChangeIntentFilter);
    603         mProfChangeListenerInitialized = true;
    604     }
    605 
    606     /* Method to handle the thermal event based on HIGH or LOW event */
    607     private void handleThermalEvent(int zoneId, int eventType, int thermalState,
    608             ThermalManager.ZoneCoolerBindingInfo zoneCoolerBindInfo) {
    609         ThermalCoolingDevice tDevice;
    610         int deviceId;
    611         int existingState, targetState;
    612         int currThrottleMask, currDethrottleMask;
    613         int index = 0;
    614 
    615         if (zoneCoolerBindInfo.getCoolingDeviceInfoList() == null)
    616             return;
    617 
    618         for (ThermalManager.ZoneCoolerBindingInfo.CoolingDeviceInfo CdeviceInfo :
    619                 zoneCoolerBindInfo.getCoolingDeviceInfoList()) {
    620             int coolingDeviceState =  thermalState /
    621                     zoneCoolerBindInfo.getZoneToCoolDevBucketSizeIndex(index);
    622             // cap it
    623             coolingDeviceState = (coolingDeviceState > (CdeviceInfo.getCoolingDeviceStates() - 1))
    624                     ? CdeviceInfo.getCoolingDeviceStates() - 1 : coolingDeviceState;
    625             int finalThrottleState = coolingDeviceState *
    626                     zoneCoolerBindInfo.getCoolDevToThrottBucketSizeIndex(index);
    627             // cap it
    628             finalThrottleState = (finalThrottleState > (CdeviceInfo.getMaxThrottleStates() - 1))
    629                     ? CdeviceInfo.getMaxThrottleStates() - 1 : finalThrottleState;
    630             index++;
    631             if (ThermalManager.THERMAL_HIGH_EVENT == eventType) {
    632                 ArrayList<Integer> throttleMaskList = CdeviceInfo.getThrottleMaskList();
    633                 if (throttleMaskList == null) continue;
    634                 // cap to avoid out of bound exception
    635                 coolingDeviceState = (coolingDeviceState > throttleMaskList.size() - 1)
    636                         ? throttleMaskList.size() - 1 : coolingDeviceState;
    637                 currThrottleMask = throttleMaskList.get(coolingDeviceState);
    638                 deviceId = CdeviceInfo.getCoolingDeviceId();
    639 
    640                 tDevice = ThermalManager.sCDevMap.get(deviceId);
    641                 if (tDevice == null)
    642                     continue;
    643 
    644                 if (currThrottleMask == ThermalManager.THROTTLE_MASK_ENABLE) {
    645                     existingState = tDevice.getThermalState();
    646                     tDevice.updateZoneState(zoneId, finalThrottleState);
    647                     targetState = tDevice.getThermalState();
    648 
    649                     /* Do not throttle if device is already in desired state.
    650                      * (We can save Sysfs write)
    651                      * */
    652                     if (existingState != targetState) throttleDevice(deviceId, targetState);
    653 
    654                 } else {
    655                      // If throttle mask is not enabled, don't do anything here.
    656                 }
    657             }
    658 
    659             if (ThermalManager.THERMAL_LOW_EVENT == eventType) {
    660                 ArrayList<Integer> dethrottleMaskList = CdeviceInfo.getDeThrottleMaskList();
    661                 if (dethrottleMaskList == null) continue;
    662                 // cap to avoid out of bound exception
    663                 coolingDeviceState = (coolingDeviceState > dethrottleMaskList.size() - 1)
    664                         ? dethrottleMaskList.size() - 1 : coolingDeviceState;
    665                 currDethrottleMask = dethrottleMaskList.get(coolingDeviceState);
    666                 deviceId = CdeviceInfo.getCoolingDeviceId();
    667 
    668                 tDevice = ThermalManager.sCDevMap.get(deviceId);
    669                 if (tDevice == null)
    670                     continue;
    671 
    672                 existingState = tDevice.getThermalState();
    673                 tDevice.updateZoneState(zoneId, finalThrottleState);
    674                 targetState = tDevice.getThermalState();
    675 
    676                 /* Do not dethrottle if device is already in desired state.
    677                  * (We can save Sysfs write) */
    678                 if ((existingState != targetState) &&
    679                         (currDethrottleMask == ThermalManager.DETHROTTLE_MASK_ENABLE)) {
    680                     throttleDevice(deviceId, targetState);
    681                 }
    682             }
    683         }
    684 
    685     }
    686 
    687     /*
    688      * defaultThrottleMethod is called for cooling devices for which an additional
    689      * plugin file is not provided. Since the throttle path and the throttle values
    690      * are known, we dont need an additional plugin to implement the policy. This info
    691      * is provided via thermal_throttle_config file. If for a cooling device,
    692      * Assumptions -
    693      * 1. If CDeviceClassPath is 'auto' this triggers a call to defaultThrottleMethod().
    694      * if a false throttle path is provided, the write fails and function exits gracefully
    695      * with a warning message.
    696      * 2. If 'auto' mode is used for CDeviceClassPath, and no throttle values are provided,
    697      * thermal state will be written.
    698      * 3. If CDeviceThrottlePath is 'auto', then throttle path will be constrcuted.
    699      * The Cooling device name should contain a subset string that matches the type for
    700      * /sys/class/thermal/cooling_deviceX/type inorder to find the right index X
    701      * 4. CDeviceThrottlePath is null no write operation will be done
    702      **/
    703     private void defaultThrottleMethod(ThermalCoolingDevice cdev, int level) {
    704         int finalValue;
    705         String throttlePath = null;
    706 
    707         if (cdev == null) return;
    708 
    709         if (level < cdev.getNumThrottleValues() - 1) {
    710             try {
    711                 ArrayList<Integer> values = cdev.getThrottleValuesList();
    712                 if (values == null || values.size() == 0) {
    713                     finalValue = level;
    714                 } else {
    715                     finalValue =  values.get(level);
    716                 }
    717 
    718                 throttlePath = cdev.getThrottlePath();
    719                 if (throttlePath == null) {
    720                     Log.w(TAG, "throttle path is null");
    721                     return;
    722                 }
    723 
    724                 if (!ThermalUtils.isFileExists(throttlePath)) {
    725                     Log.w(TAG, "invalid throttle path for cooling device:" + cdev.getDeviceName());
    726                     return;
    727                 }
    728 
    729                 if (ThermalUtils.writeSysfs(throttlePath, finalValue) == -1) {
    730                     Log.w(TAG, "write to sysfs failed");
    731                 }
    732             } catch (IndexOutOfBoundsException e) {
    733                 Log.w(TAG, "IndexOutOfBoundsException caught in defaultThrottleMethod()");
    734             }
    735         }
    736     }
    737 
    738     /* Method to throttle cooling device */
    739     private void throttleDevice(int coolingDevId, int throttleLevel) {
    740         /* Retrieve the cooling device based on ID */
    741         ThermalCoolingDevice dev = ThermalManager.sCDevMap.get(coolingDevId);
    742         if (dev != null) {
    743             if (dev.getClassPath() != null && dev.getClassPath().equalsIgnoreCase("auto")) {
    744                 defaultThrottleMethod(dev, throttleLevel);
    745             } else {
    746                 Class c = dev.getDeviceClass();
    747                 Method throt = dev.getThrottleMethod();
    748                 if (throt == null)
    749                     return;
    750                 Object arglist[] = new Object[1];
    751                 arglist[0] = new Integer(throttleLevel);
    752 
    753                 // Invoke the throttle method passing the throttle level as parameter
    754                 try {
    755                     throt.invoke(c, arglist);
    756                 } catch (IllegalAccessException e) {
    757                     Log.i(TAG, "IllegalAccessException caught throttleDevice() ");
    758                 } catch (IllegalArgumentException e) {
    759                     Log.i(TAG, "IllegalArgumentException caught throttleDevice() ");
    760                 } catch (ExceptionInInitializerError e) {
    761                     Log.i(TAG, "ExceptionInInitializerError caught throttleDevice() ");
    762                 } catch (SecurityException e) {
    763                     Log.i(TAG, "SecurityException caught throttleDevice() ");
    764                 } catch (InvocationTargetException e) {
    765                     Log.i(TAG, "InvocationTargetException caught throttleDevice() ");
    766                 }
    767             }
    768         } else {
    769             Log.i(TAG, "throttleDevice: Unable to retrieve cooling device " + coolingDevId);
    770         }
    771     }
    772 
    773     public void unregisterReceivers() {
    774         if (mContext != null) {
    775             mContext.unregisterReceiver(mThermalIntentReceiver);
    776             // During Thermal Service init, when parsing fails, we
    777             // unregister all receivers here. mProfChangeReceiver
    778             // might not have been initialized at that time because
    779             // we initialize this only after starting the Default profile.
    780             if (mProfChangeListenerInitialized) {
    781                 mContext.unregisterReceiver(mProfChangeReceiver);
    782             }
    783         }
    784     }
    785 }
    786