/* * Copyright 2014 Intel Corporation All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intel.thermal; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.SystemProperties; import android.util.Log; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Hashtable; /** * The ThermalCooling class parses the thermal_throttle_config.xml. This class * receives Thermal Intents and takes appropriate actions based on the policies * configured in the xml file. * * @hide */ public class ThermalCooling { private static final String TAG = "ThermalCooling"; private static final String THERMAL_SHUTDOWN_NOTIFY_PATH = "/sys/module/intel_mid_osip/parameters/force_shutdown_occured"; private Context mContext; // count to keep track of zones in critical state, waiting for shutdown private int mCriticalZonesCount = 0; private static final Object sCriticalZonesCountLock = new Object(); private ThermalZoneReceiver mThermalIntentReceiver = new ThermalZoneReceiver(); private ProfileChangeReceiver mProfChangeReceiver = new ProfileChangeReceiver(); private boolean mProfChangeListenerInitialized = false; /** * This is the parser class which parses the thermal_throttle_config.xml * file. */ protected enum MetaTag { ENUM_THROTTLEVALUES, ENUM_THROTTLEMASK, ENUM_DETHROTTLEMASK, ENUM_UNKNOWN } public class ThermalParser { private static final String THERMAL_THROTTLE_CONFIG = "thermalthrottleconfig"; private static final String CDEVINFO = "ContributingDeviceInfo"; private static final String ZONETHROTINFO = "ZoneThrottleInfo"; private static final String COOLINGDEVICEINFO = "CoolingDeviceInfo"; private static final String THROTTLEMASK = "ThrottleDeviceMask"; private static final String DETHROTTLEMASK = "DethrottleDeviceMask"; private static final String THROTTLEVALUES = "ThrottleValues"; private static final String COOLINGDEVICESTATES = "CoolingDeviceStates"; private static final String PROFILE = "Profile"; private ArrayList mTempMaskList; private ArrayList mTempThrottleValuesList;; private boolean done = false; XmlPullParserFactory mFactory; XmlPullParser mParser; ThermalCoolingDevice mDevice = null; /* Hashtable of (ZoneID and ZoneCoolerBindingInfo object) */ Hashtable mZoneCoolerBindMap = null; String mCurProfileName = ThermalManager.DEFAULT_PROFILE_NAME; int mNumProfiles = 0; ThermalManager.ZoneCoolerBindingInfo mZone = null; FileReader mInputStream = null; ThermalParser(String fname) { try { mFactory = XmlPullParserFactory.newInstance( System.getProperty(XmlPullParserFactory.PROPERTY_NAME), null); mFactory.setNamespaceAware(true); mParser = mFactory.newPullParser(); } catch (XmlPullParserException xppe) { Log.e(TAG, "mParser NewInstance Exception"); } try { mInputStream = new FileReader(fname); if (mInputStream == null) return; if (mParser != null) { mParser.setInput(mInputStream); } mDevice = null; mZone = null; } catch (XmlPullParserException xppe) { Log.e(TAG, "mParser setInput XmlPullParserException"); } catch (FileNotFoundException e) { Log.e(TAG, "mParser setInput FileNotFoundException"); } } ThermalParser() { mParser = mContext.getResources(). getXml(ThermalManager.sThrottleFileXmlId); } public boolean parse() { if (ThermalManager.sIsOverlays == false && mInputStream == null) return false; /* if mParser is null, close any open stream before exiting */ if (mParser == null) { try { if (mInputStream != null) { mInputStream.close(); } } catch (IOException e) { Log.i(TAG, "IOException caught in parse() function"); } return false; } boolean ret = true; MetaTag tag = MetaTag.ENUM_UNKNOWN; try { int mEventType = mParser.getEventType(); while (mEventType != XmlPullParser.END_DOCUMENT && !done) { switch (mEventType) { case XmlPullParser.START_DOCUMENT: Log.i(TAG, "StartDocument"); break; case XmlPullParser.START_TAG: String tagName = mParser.getName(); boolean isMetaTag = false; if (tagName != null && tagName.equalsIgnoreCase(THROTTLEVALUES)) { tag = MetaTag.ENUM_THROTTLEVALUES; isMetaTag = true; } else if (tagName != null && tagName.equalsIgnoreCase(THROTTLEMASK)) { tag = MetaTag.ENUM_THROTTLEMASK; isMetaTag = true; } else if (tagName != null && tagName.equalsIgnoreCase(DETHROTTLEMASK)) { tag = MetaTag.ENUM_DETHROTTLEMASK; isMetaTag = true; } if (isMetaTag) { ret = processMetaTag(tagName, tag); } else { ret = processStartElement(tagName); } if (!ret) { if (mInputStream != null) mInputStream.close(); return false; } break; case XmlPullParser.END_TAG: processEndElement(mParser.getName()); break; } mEventType = mParser.next(); } } catch (XmlPullParserException xppe) { Log.i(TAG, "XmlPullParserException caught in parse():" + xppe.getMessage()); ret = false; } catch (IOException e) { Log.i(TAG, "IOException caught in parse():" + e.getMessage()); ret = false; } finally { try { // end of parsing, close the stream // close is moved here, since if there is an exception // while parsing doc, input stream needs to be closed if (mInputStream != null) { mInputStream.close(); } } catch (IOException e) { Log.i(TAG, "IOException caught in parse() function"); ret = false; } return ret; } } public boolean processMetaTag(String tagName, MetaTag tagId) { if (mParser == null || tagName == null) return false; ArrayList tempList = new ArrayList(); try { int eventType = mParser.next(); while (true) { if (eventType == XmlPullParser.START_TAG) { tempList.add(Integer.parseInt(mParser.nextText())); } else if (eventType == XmlPullParser.END_TAG && mParser.getName().equalsIgnoreCase(tagName)) { break; } eventType = mParser.next(); } } catch (XmlPullParserException xppe) { Log.e(TAG, "XmlPullParserException:" + xppe.getMessage()); return false; } catch (IOException ioe) { Log.e(TAG, "IOException:" + ioe.getMessage()); return false; } switch(tagId) { case ENUM_THROTTLEVALUES: if (mDevice == null) { return false; } else { // add throttle value for TCRITICAL (same as last value) tempList.add(tempList.get(tempList.size() - 1)); mDevice.setThrottleValuesList(tempList); } break; case ENUM_THROTTLEMASK: if (mZone == null || mZone.getLastCoolingDeviceInstance() == null) { return false; } else { // Always throttle at CRITICAL state (last state) tempList.add(1); mZone.getLastCoolingDeviceInstance().setThrottleMaskList(tempList); } break; case ENUM_DETHROTTLEMASK: if (mZone == null || mZone.getLastCoolingDeviceInstance() == null) { return false; } else { // Dethrottling at CRITICAL state (last state) is dontcare condition tempList.add(0); mZone.getLastCoolingDeviceInstance().setDeThrottleMaskList(tempList); } break; default: return false; } return true; } boolean processStartElement(String name) { if (name == null) return false; boolean ret = true; try { if (name.equalsIgnoreCase(CDEVINFO)) { if (mDevice == null) mDevice = new ThermalCoolingDevice(); } else if (name.equalsIgnoreCase(ZONETHROTINFO)) { if (mZone == null) { mZone = new ThermalManager.ZoneCoolerBindingInfo(); } if (mZoneCoolerBindMap == null) { mZoneCoolerBindMap = new Hashtable(); } } else if (name.equalsIgnoreCase(PROFILE)) { mNumProfiles++; if (mZoneCoolerBindMap == null) { mZoneCoolerBindMap = new Hashtable(); } } else if (name.equalsIgnoreCase(COOLINGDEVICEINFO) && mZone != null) { if (mZone.getCoolingDeviceInfoList() == null) { mZone.initializeCoolingDeviceInfoList(); } mZone.createNewCoolingDeviceInstance(); } else { // Retrieve zone and cooling device mapping if (name.equalsIgnoreCase("ZoneID") && mZone != null) { mZone.setZoneID(Integer.parseInt(mParser.nextText())); } else if (name.equalsIgnoreCase("CriticalShutDown") && mZone != null) { mZone.setCriticalActionShutdown(Integer.parseInt(mParser.nextText())); } else if (name.equalsIgnoreCase(THROTTLEMASK) && mZone != null) { mTempMaskList = new ArrayList(); } else if (name.equalsIgnoreCase(DETHROTTLEMASK) && mZone != null) { mTempMaskList = new ArrayList(); } else if (name.equalsIgnoreCase("CoolingDevId") && mZone != null) { mZone.getLastCoolingDeviceInstance().setCoolingDeviceId( Integer.parseInt(mParser.nextText())); } else if (name.equalsIgnoreCase(COOLINGDEVICESTATES) && mZone != null) { // Increase cooling device states by 1, required for CRITICAL state mZone.getLastCoolingDeviceInstance().setCoolingDeviceStates( Integer.parseInt(mParser.nextText()) + 1); } // Retrieve cooling device information if (name.equalsIgnoreCase("CDeviceName") && mDevice != null) { mDevice.setDeviceName(mParser.nextText()); } else if (name.equalsIgnoreCase("CDeviceID") && mDevice != null) { mDevice.setDeviceId(Integer.parseInt(mParser.nextText())); } else if (name.equalsIgnoreCase("CDeviceClassPath") && mDevice != null) { mDevice.setClassPath(mParser.nextText()); } else if (name.equalsIgnoreCase("CDeviceThrottlePath") && mDevice != null) { mDevice.setThrottlePath(mParser.nextText()); } else if (name.equalsIgnoreCase("Name")) { mCurProfileName = mParser.nextText(); } } } catch (XmlPullParserException e) { Log.i(TAG, "XmlPullParserException caught in processStartElement()"); ret = false; } catch (IOException e) { Log.i(TAG, "IOException caught in processStartElement()"); ret = false; } finally { return ret; } } void processEndElement(String name) { if (name == null) return; if (name.equalsIgnoreCase(CDEVINFO) && mDevice != null) { // if cooling dev suports less then DEFAULT throttle values donot add to map. if (mDevice.getNumThrottleValues() < ThermalManager.DEFAULT_NUM_THROTTLE_VALUES) { Log.i(TAG, "cooling dev:" + mDevice.getDeviceName() + " deactivated! throttle values < " + ThermalManager.DEFAULT_NUM_THROTTLE_VALUES); mDevice = null; return; } if (mDevice.getThrottlePath().equals("auto")) { mDevice.setThrottlePath("auto"); } if (loadCoolingDevice(mDevice)) { ThermalManager.sCDevMap.put(mDevice.getDeviceId(), mDevice); } mDevice = null; } else if (name.equalsIgnoreCase(ZONETHROTINFO) && mZone != null) { mZone.printAttributes(); if (mZoneCoolerBindMap != null) { mZoneCoolerBindMap.put(mZone.getZoneID(), mZone); } mZone = null; } else if (name.equalsIgnoreCase(PROFILE)) { if (mZoneCoolerBindMap != null) { ThermalManager.sProfileBindMap.put(mCurProfileName, mZoneCoolerBindMap); mZoneCoolerBindMap = new Hashtable(); } } else if (name.equalsIgnoreCase(THERMAL_THROTTLE_CONFIG)) { Log.i(TAG, "Parsing Finished.."); // This indicates we have not seen any tag. // Consider it as if we have only one 'Default' Profile. if (mNumProfiles == 0 && mZoneCoolerBindMap != null) { ThermalManager.sProfileBindMap.put(mCurProfileName, mZoneCoolerBindMap); } done = true; } else if (name.equalsIgnoreCase(COOLINGDEVICEINFO) && mZone != null) { ThermalManager.ZoneCoolerBindingInfo.CoolingDeviceInfo cDevInfo; cDevInfo = mZone.getLastCoolingDeviceInstance(); if (cDevInfo != null) { ThermalCoolingDevice cDev = ThermalManager.sCDevMap .get(cDevInfo.getCoolingDeviceId()); if (cDev == null) return; int cds = cDevInfo.getCoolingDeviceStates(); // check the CDS against the number of throttle values exposed. // If exceeds, cap it. if (cds > cDev.getNumThrottleValues()) { cDevInfo.setCoolingDeviceStates(cDev.getNumThrottleValues()); Log.i(TAG, "capping cdevid: " + cDevInfo.getCoolingDeviceId() + " to " + cDev.getNumThrottleValues() + " states"); } if (cDevInfo.checkMaskList(cDev.getNumThrottleValues())) { // add only active cooling devices to list mZone.addCoolingDeviceToList(cDevInfo); } } } } } private void configureDynamicTurbo() { // Disable Dynamic Turbo based on the system property int indx = ThermalUtils.getCoolingDeviceIndexContains("SoC"); if (indx != -1 && !ThermalManager.sIsDynamicTurboEnabled) { String path = ThermalManager.sCoolingDeviceBasePath + indx + ThermalManager.sCoolingDeviceState; ThermalUtils.writeSysfs(path, ThermalManager.DISABLE_DYNAMIC_TURBO); } } public boolean init(Context context) { Log.i(TAG, "Thermal Cooling manager init() called"); mContext = context; ThermalParser parser; if (!ThermalManager.sIsOverlays) { parser = new ThermalParser(ThermalManager.sThrottleFilePath); } else { parser = new ThermalParser(); } if (parser == null || !parser.parse()) { Log.i(TAG, "thermal_throttle_config.xml parsing failed"); return false; } // Set this sZoneCoolerBindMap to the DefaultProfile Map ThermalManager.setCurBindMap(ThermalManager.DEFAULT_PROFILE_NAME); // Register for thermal zone state changed notifications IntentFilter filter = new IntentFilter(); filter.addAction(ThermalManager.ACTION_THERMAL_ZONE_STATE_CHANGED); mContext.registerReceiver(mThermalIntentReceiver, filter); configureDynamicTurbo(); return true; } private final class ProfileChangeReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(ThermalManager.ACTION_CHANGE_THERMAL_PROFILE)) { String profName = intent.getStringExtra(ThermalManager.EXTRA_PROFILE); if (profName != null) { ThermalManager.changeThermalProfile(profName); } } } } private void incrementCrticalZoneCount() { synchronized(sCriticalZonesCountLock) { mCriticalZonesCount++; } } private final class ThermalZoneReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String zoneName = intent.getStringExtra(ThermalManager.EXTRA_NAME); String profName = intent.getStringExtra(ThermalManager.EXTRA_PROFILE); int thermZone = intent.getIntExtra(ThermalManager.EXTRA_ZONE, -1); int thermState = intent.getIntExtra(ThermalManager.EXTRA_STATE, 0); int thermEvent = intent.getIntExtra(ThermalManager.EXTRA_EVENT, 0); int zoneTemp = intent.getIntExtra(ThermalManager.EXTRA_TEMP, 0); // Assume 'Default' profile if there is no profile parameter // as part of the intent. if (profName == null) { profName = ThermalManager.DEFAULT_PROFILE_NAME; } Log.i(TAG, "Received THERMAL INTENT:(ProfileName, ZoneName, State, EventType, Temp):" + "(" + profName + ", " + zoneName + ", " + thermState + ", " + ThermalZone.getEventTypeAsString(thermEvent) + ", " + zoneTemp + ")"); Hashtable mBindMap = ThermalManager.getBindMap(profName); if (mBindMap == null) { Log.i(TAG, "mBindMap null inside ThermalZoneReceiver"); return; } ThermalManager.ZoneCoolerBindingInfo zoneCoolerBindInfo = mBindMap.get(thermZone); if (zoneCoolerBindInfo == null) { Log.i(TAG, "zoneCoolerBindInfo null for zoneID" + thermZone); return; } boolean flag = zoneCoolerBindInfo.getCriticalActionShutdown() == 1; int lastState = zoneCoolerBindInfo.getLastState(); if (thermState < lastState) { ThermalManager.updateZoneCriticalPendingMap(thermZone, ThermalManager.CRITICAL_FALSE); } else if (thermState == lastState && flag) { /* no telephony support, so (!isEmergencyCallOnGoing) is true */ if (true) { doShutdown(); } else { // increment the count of zones in critical state pending on shutdown ThermalManager.updateZoneCriticalPendingMap(thermZone, ThermalManager.CRITICAL_TRUE); } } /* if THERMALOFF is the zone state, it is guaranteed that the zone has transitioned from a higher state, due to a low event, to THERMALOFF.Hence take de-throttling action corresponding to NORMAL */ if (thermState == ThermalManager.THERMAL_STATE_OFF) { thermState = ThermalManager.THERMAL_STATE_NORMAL; } handleThermalEvent(thermZone, thermEvent, thermState, zoneCoolerBindInfo); } } private boolean loadCoolingDevice(ThermalCoolingDevice device) { Class cls; Method throttleMethod; String classPath = device.getClassPath(); if (classPath == null) { Log.i(TAG, "ClassPath not found"); return false; } if (classPath.equalsIgnoreCase("none") || classPath.equalsIgnoreCase("auto") || classPath.equalsIgnoreCase("AppAgent")) { Log.i(TAG, "ClassPath: none/auto/AppAgent"); return true; } /* Load the cooling device class */ try { cls = Class.forName(classPath); device.setDeviceClass(cls); } catch (Throwable e) { Log.i(TAG, "Unable to load class " + classPath); return false; } /* Initialize the cooling device class */ try { Class partypes[] = new Class[3]; partypes[0] = Context.class; partypes[1] = String.class; partypes[2] = ArrayList.class; Method init = cls.getMethod("init", partypes); Object arglist[] = new Object[3]; arglist[0] = mContext; arglist[1] = device.getThrottlePath(); arglist[2] = device.getThrottleValuesList(); init.invoke(cls, arglist); } catch (NoSuchMethodException e) { Log.i(TAG, "NoSuchMethodException caught in device class init: " + classPath); } catch (SecurityException e) { Log.i(TAG, "SecurityException caught in device class init: " + classPath); } catch (IllegalAccessException e) { Log.i(TAG, "IllegalAccessException caught in device class init: " + classPath); } catch (IllegalArgumentException e) { Log.i(TAG, "IllegalArgumentException caught in device class init: " + classPath); } catch (ExceptionInInitializerError e) { Log.i(TAG, "ExceptionInInitializerError caught in device class init: " + classPath); } catch (InvocationTargetException e) { Log.i(TAG, "InvocationTargetException caught in device class init: " + classPath); } /* Get the throttleDevice method from cooling device class */ try { Class partypes[] = new Class[1]; partypes[0] = Integer.TYPE; throttleMethod = cls.getMethod("throttleDevice", partypes); device.setThrottleMethod(throttleMethod); } catch (NoSuchMethodException e) { Log.i(TAG, "NoSuchMethodException caught initializing throttle function"); } catch (SecurityException e) { Log.i(TAG, "SecurityException caught initializing throttle function"); } return true; } public void doShutdown() { ThermalUtils.writeSysfs(THERMAL_SHUTDOWN_NOTIFY_PATH, 1); /* We must avoid reboot after shutdown. */ SystemProperties.set("sys.property_forcedshutdown", "1"); Intent criticalIntent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN); criticalIntent.putExtra(Intent.EXTRA_KEY_CONFIRM, false); criticalIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Log.i(TAG, "Thermal Service initiating shutdown"); mContext.startActivity(criticalIntent); } public void registerProfChangeListener() { IntentFilter profChangeIntentFilter = new IntentFilter(); profChangeIntentFilter.addAction(ThermalManager.ACTION_CHANGE_THERMAL_PROFILE); // TODO: add some permission (BRICK ??) to protect it from third party apps mContext.registerReceiver(mProfChangeReceiver, profChangeIntentFilter); mProfChangeListenerInitialized = true; } /* Method to handle the thermal event based on HIGH or LOW event */ private void handleThermalEvent(int zoneId, int eventType, int thermalState, ThermalManager.ZoneCoolerBindingInfo zoneCoolerBindInfo) { ThermalCoolingDevice tDevice; int deviceId; int existingState, targetState; int currThrottleMask, currDethrottleMask; int index = 0; if (zoneCoolerBindInfo.getCoolingDeviceInfoList() == null) return; for (ThermalManager.ZoneCoolerBindingInfo.CoolingDeviceInfo CdeviceInfo : zoneCoolerBindInfo.getCoolingDeviceInfoList()) { int coolingDeviceState = thermalState / zoneCoolerBindInfo.getZoneToCoolDevBucketSizeIndex(index); // cap it coolingDeviceState = (coolingDeviceState > (CdeviceInfo.getCoolingDeviceStates() - 1)) ? CdeviceInfo.getCoolingDeviceStates() - 1 : coolingDeviceState; int finalThrottleState = coolingDeviceState * zoneCoolerBindInfo.getCoolDevToThrottBucketSizeIndex(index); // cap it finalThrottleState = (finalThrottleState > (CdeviceInfo.getMaxThrottleStates() - 1)) ? CdeviceInfo.getMaxThrottleStates() - 1 : finalThrottleState; index++; if (ThermalManager.THERMAL_HIGH_EVENT == eventType) { ArrayList throttleMaskList = CdeviceInfo.getThrottleMaskList(); if (throttleMaskList == null) continue; // cap to avoid out of bound exception coolingDeviceState = (coolingDeviceState > throttleMaskList.size() - 1) ? throttleMaskList.size() - 1 : coolingDeviceState; currThrottleMask = throttleMaskList.get(coolingDeviceState); deviceId = CdeviceInfo.getCoolingDeviceId(); tDevice = ThermalManager.sCDevMap.get(deviceId); if (tDevice == null) continue; if (currThrottleMask == ThermalManager.THROTTLE_MASK_ENABLE) { existingState = tDevice.getThermalState(); tDevice.updateZoneState(zoneId, finalThrottleState); targetState = tDevice.getThermalState(); /* Do not throttle if device is already in desired state. * (We can save Sysfs write) * */ if (existingState != targetState) throttleDevice(deviceId, targetState); } else { // If throttle mask is not enabled, don't do anything here. } } if (ThermalManager.THERMAL_LOW_EVENT == eventType) { ArrayList dethrottleMaskList = CdeviceInfo.getDeThrottleMaskList(); if (dethrottleMaskList == null) continue; // cap to avoid out of bound exception coolingDeviceState = (coolingDeviceState > dethrottleMaskList.size() - 1) ? dethrottleMaskList.size() - 1 : coolingDeviceState; currDethrottleMask = dethrottleMaskList.get(coolingDeviceState); deviceId = CdeviceInfo.getCoolingDeviceId(); tDevice = ThermalManager.sCDevMap.get(deviceId); if (tDevice == null) continue; existingState = tDevice.getThermalState(); tDevice.updateZoneState(zoneId, finalThrottleState); targetState = tDevice.getThermalState(); /* Do not dethrottle if device is already in desired state. * (We can save Sysfs write) */ if ((existingState != targetState) && (currDethrottleMask == ThermalManager.DETHROTTLE_MASK_ENABLE)) { throttleDevice(deviceId, targetState); } } } } /* * defaultThrottleMethod is called for cooling devices for which an additional * plugin file is not provided. Since the throttle path and the throttle values * are known, we dont need an additional plugin to implement the policy. This info * is provided via thermal_throttle_config file. If for a cooling device, * Assumptions - * 1. If CDeviceClassPath is 'auto' this triggers a call to defaultThrottleMethod(). * if a false throttle path is provided, the write fails and function exits gracefully * with a warning message. * 2. If 'auto' mode is used for CDeviceClassPath, and no throttle values are provided, * thermal state will be written. * 3. If CDeviceThrottlePath is 'auto', then throttle path will be constrcuted. * The Cooling device name should contain a subset string that matches the type for * /sys/class/thermal/cooling_deviceX/type inorder to find the right index X * 4. CDeviceThrottlePath is null no write operation will be done **/ private void defaultThrottleMethod(ThermalCoolingDevice cdev, int level) { int finalValue; String throttlePath = null; if (cdev == null) return; if (level < cdev.getNumThrottleValues() - 1) { try { ArrayList values = cdev.getThrottleValuesList(); if (values == null || values.size() == 0) { finalValue = level; } else { finalValue = values.get(level); } throttlePath = cdev.getThrottlePath(); if (throttlePath == null) { Log.w(TAG, "throttle path is null"); return; } if (!ThermalUtils.isFileExists(throttlePath)) { Log.w(TAG, "invalid throttle path for cooling device:" + cdev.getDeviceName()); return; } if (ThermalUtils.writeSysfs(throttlePath, finalValue) == -1) { Log.w(TAG, "write to sysfs failed"); } } catch (IndexOutOfBoundsException e) { Log.w(TAG, "IndexOutOfBoundsException caught in defaultThrottleMethod()"); } } } /* Method to throttle cooling device */ private void throttleDevice(int coolingDevId, int throttleLevel) { /* Retrieve the cooling device based on ID */ ThermalCoolingDevice dev = ThermalManager.sCDevMap.get(coolingDevId); if (dev != null) { if (dev.getClassPath() != null && dev.getClassPath().equalsIgnoreCase("auto")) { defaultThrottleMethod(dev, throttleLevel); } else { Class c = dev.getDeviceClass(); Method throt = dev.getThrottleMethod(); if (throt == null) return; Object arglist[] = new Object[1]; arglist[0] = new Integer(throttleLevel); // Invoke the throttle method passing the throttle level as parameter try { throt.invoke(c, arglist); } catch (IllegalAccessException e) { Log.i(TAG, "IllegalAccessException caught throttleDevice() "); } catch (IllegalArgumentException e) { Log.i(TAG, "IllegalArgumentException caught throttleDevice() "); } catch (ExceptionInInitializerError e) { Log.i(TAG, "ExceptionInInitializerError caught throttleDevice() "); } catch (SecurityException e) { Log.i(TAG, "SecurityException caught throttleDevice() "); } catch (InvocationTargetException e) { Log.i(TAG, "InvocationTargetException caught throttleDevice() "); } } } else { Log.i(TAG, "throttleDevice: Unable to retrieve cooling device " + coolingDevId); } } public void unregisterReceivers() { if (mContext != null) { mContext.unregisterReceiver(mThermalIntentReceiver); // During Thermal Service init, when parsing fails, we // unregister all receivers here. mProfChangeReceiver // might not have been initialized at that time because // we initialize this only after starting the Default profile. if (mProfChangeListenerInitialized) { mContext.unregisterReceiver(mProfChangeReceiver); } } } }