OSDN Git Service

Add cooling device into thermal service
authorWei Wang <wvw@google.com>
Wed, 3 Apr 2019 21:58:42 +0000 (14:58 -0700)
committerWei Wang <wvw@google.com>
Fri, 5 Apr 2019 21:34:31 +0000 (14:34 -0700)
This is for statsd to log new metrics, as statsd has moved to use
thermal service in framework instead of connecting to HAL directly.

Bug: 119688911
Test: Build and dumpsys thermalservice
Test: atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
Change-Id: Ib334c448c3615bf9d1cb0f1b6c2dd8a83d44f371

core/java/android/os/CoolingDevice.aidl [new file with mode: 0644]
core/java/android/os/CoolingDevice.java [new file with mode: 0644]
core/java/android/os/IThermalService.aidl
core/java/android/os/Temperature.java
services/core/java/com/android/server/power/ThermalManagerService.java
services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java

diff --git a/core/java/android/os/CoolingDevice.aidl b/core/java/android/os/CoolingDevice.aidl
new file mode 100644 (file)
index 0000000..478e4bd
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** 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 android.os;
+
+parcelable CoolingDevice;
diff --git a/core/java/android/os/CoolingDevice.java b/core/java/android/os/CoolingDevice.java
new file mode 100644 (file)
index 0000000..0e86a38
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2019 The Android Open Source Project
+ *
+ * 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 android.os;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.hardware.thermal.V2_0.CoolingType;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Cooling device values used by IThermalService.
+ *
+ * @hide
+ */
+public final class CoolingDevice implements Parcelable {
+    /**
+     * Current throttle state of the cooling device. The value can any unsigned integer
+     * numbers between 0 and max_state defined in its driver, usually representing the
+     * associated device's power state. 0 means device is not in throttling, higher value
+     * means deeper throttling.
+     */
+    private final long mValue;
+    /** A cooling device type from ThermalHAL */
+    private final int mType;
+    /** Name of this cooling device */
+    private final String mName;
+
+    @IntDef(prefix = { "TYPE_" }, value = {
+            TYPE_FAN,
+            TYPE_BATTERY,
+            TYPE_CPU,
+            TYPE_GPU,
+            TYPE_MODEM,
+            TYPE_NPU,
+            TYPE_COMPONENT,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Type {}
+
+    /** Keep in sync with hardware/interfaces/thermal/2.0/types.hal */
+    /** Fan for active cooling */
+    public static final int TYPE_FAN = CoolingType.FAN;
+    /** Battery charging cooling deivice */
+    public static final int TYPE_BATTERY = CoolingType.BATTERY;
+    /** CPU cooling deivice */
+    public static final int TYPE_CPU = CoolingType.CPU;
+    /** GPU cooling deivice */
+    public static final int TYPE_GPU = CoolingType.GPU;
+    /** Modem cooling deivice */
+    public static final int TYPE_MODEM = CoolingType.MODEM;
+    /** NPU/TPU cooling deivice */
+    public static final int TYPE_NPU = CoolingType.NPU;
+    /** Generic passive cooling deivice */
+    public static final int TYPE_COMPONENT = CoolingType.COMPONENT;
+
+    /**
+     * Verify a valid cooling device type.
+     *
+     * @return true if a cooling device type is valid otherwise false.
+     */
+    public static boolean isValidType(@Type int type) {
+        return type >= TYPE_FAN && type <= TYPE_COMPONENT;
+    }
+
+    public CoolingDevice(long value, @Type int type, @NonNull String name) {
+        Preconditions.checkArgument(isValidType(type), "Invalid Type");
+        mValue = value;
+        mType = type;
+        mName = Preconditions.checkStringNotEmpty(name);
+    }
+
+    /**
+     * Return the cooling device value.
+     *
+     * @return a cooling device value in int.
+     */
+    public long getValue() {
+        return mValue;
+    }
+
+    /**
+     * Return the cooling device type.
+     *
+     * @return a cooling device type: TYPE_*
+     */
+    public @Type int getType() {
+        return mType;
+    }
+
+    /**
+     * Return the cooling device name.
+     *
+     * @return a cooling device name as String.
+     */
+    public String getName() {
+        return mName;
+    }
+
+    @Override
+    public String toString() {
+        return "CoolingDevice{mValue=" + mValue + ", mType=" + mType + ", mName=" + mName + "}";
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = mName.hashCode();
+        hash = 31 * hash + Long.hashCode(mValue);
+        hash = 31 * hash + mType;
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof CoolingDevice)) {
+            return false;
+        }
+        CoolingDevice other = (CoolingDevice) o;
+        return other.mValue == mValue && other.mType == mType && other.mName.equals(mName);
+    }
+
+    @Override
+    public void writeToParcel(Parcel p, int flags) {
+        p.writeLong(mValue);
+        p.writeInt(mType);
+        p.writeString(mName);
+    }
+
+    public static final @android.annotation.NonNull Parcelable.Creator<CoolingDevice> CREATOR =
+            new Parcelable.Creator<CoolingDevice>() {
+                @Override
+                public CoolingDevice createFromParcel(Parcel p) {
+                    long value = p.readLong();
+                    int type = p.readInt();
+                    String name = p.readString();
+                    return new CoolingDevice(value, type, name);
+                }
+
+                @Override
+                public CoolingDevice[] newArray(int size) {
+                    return new CoolingDevice[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
index 9280cb9..8c98960 100644 (file)
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.os.CoolingDevice;
 import android.os.IThermalEventListener;
 import android.os.IThermalStatusListener;
 import android.os.Temperature;
@@ -52,7 +53,7 @@ interface IThermalService {
 
     /**
       * Get current temperature with its throttling status.
-      * @return list of android.os.Temperature
+      * @return list of {@link android.os.Temperature}.
       * {@hide}
       */
     List<Temperature> getCurrentTemperatures();
@@ -87,4 +88,19 @@ interface IThermalService {
       * {@hide}
       */
     int getCurrentThermalStatus();
+
+    /**
+      * Get current cooling devices.
+      * @return list of {@link android.os.CoolingDevice}.
+      * {@hide}
+      */
+    List<CoolingDevice> getCurrentCoolingDevices();
+
+    /**
+      * Get current cooling devices on given type.
+      * @param type the cooling device type to query.
+      * @return list of {@link android.os.CoolingDevice}.
+      * {@hide}
+      */
+    List<CoolingDevice> getCurrentCoolingDevicesWithType(in int type);
 }
index be7e824..7caffcd 100644 (file)
 package android.os;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.hardware.thermal.V2_0.TemperatureType;
 import android.hardware.thermal.V2_0.ThrottlingSeverity;
 
+import com.android.internal.util.Preconditions;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -30,13 +33,13 @@ import java.lang.annotation.RetentionPolicy;
  */
 public final class Temperature implements Parcelable {
     /** Temperature value */
-    private float mValue;
-    /** A temperature type from ThermalHAL */
-    private int mType;
-    /** Name of this temperature */
-    private String mName;
+    private final float mValue;
+    /** A Temperature type from ThermalHAL */
+    private final int mType;
+    /** Name of this Temperature */
+    private final String mName;
     /** The level of the sensor is currently in throttling */
-    private int mStatus;
+    private final int mStatus;
 
     @IntDef(prefix = { "THROTTLING_" }, value = {
             THROTTLING_NONE,
@@ -75,7 +78,7 @@ public final class Temperature implements Parcelable {
     @Retention(RetentionPolicy.SOURCE)
     public @interface Type {}
 
-    /* Keep in sync with hardware/interfaces/thermal/2.0/types.hal */
+    /** Keep in sync with hardware/interfaces/thermal/2.0/types.hal */
     public static final int TYPE_UNKNOWN = TemperatureType.UNKNOWN;
     public static final int TYPE_CPU = TemperatureType.CPU;
     public static final int TYPE_GPU = TemperatureType.GPU;
@@ -89,9 +92,9 @@ public final class Temperature implements Parcelable {
     public static final int TYPE_NPU = TemperatureType.NPU;
 
     /**
-     * Verify a valid temperature type.
+     * Verify a valid Temperature type.
      *
-     * @return true if a temperature type is valid otherwise false.
+     * @return true if a Temperature type is valid otherwise false.
      */
     public static boolean isValidType(@Type int type) {
         return type >= TYPE_UNKNOWN && type <= TYPE_NPU;
@@ -106,67 +109,75 @@ public final class Temperature implements Parcelable {
         return status >= THROTTLING_NONE && status <= THROTTLING_SHUTDOWN;
     }
 
-    public Temperature() {
-        this(Float.NaN, TYPE_UNKNOWN, "", THROTTLING_NONE);
-    }
-
-    public Temperature(float value, @Type int type, String name, @ThrottlingStatus int status) {
+    public Temperature(float value, @Type int type,
+            @NonNull String name, @ThrottlingStatus int status) {
+        Preconditions.checkArgument(isValidType(type), "Invalid Type");
+        Preconditions.checkArgument(isValidStatus(status) , "Invalid Status");
         mValue = value;
-        mType = isValidType(type) ? type : TYPE_UNKNOWN;
-        mName = name;
-        mStatus = isValidStatus(status) ? status : THROTTLING_NONE;
+        mType = type;
+        mName = Preconditions.checkStringNotEmpty(name);
+        mStatus = status;
     }
 
     /**
-     * Return the temperature value.
+     * Return the Temperature value.
      *
-     * @return a temperature value in floating point could be NaN.
+     * @return a Temperature value in floating point could be NaN.
      */
     public float getValue() {
         return mValue;
     }
 
     /**
-     * Return the temperature type.
+     * Return the Temperature type.
      *
-     * @return a temperature type: TYPE_*
+     * @return a Temperature type: TYPE_*
      */
     public @Type int getType() {
         return mType;
     }
 
     /**
-     * Return the temperature name.
+     * Return the Temperature name.
      *
-     * @return a temperature name as String.
+     * @return a Temperature name as String.
      */
     public String getName() {
         return mName;
     }
 
     /**
-     * Return the temperature throttling status.
+     * Return the Temperature throttling status.
      *
-     * @return a temperature throttling status: THROTTLING_*
+     * @return a Temperature throttling status: THROTTLING_*
      */
     public @ThrottlingStatus int getStatus() {
         return mStatus;
     }
 
-    private Temperature(Parcel p) {
-        readFromParcel(p);
+    @Override
+    public String toString() {
+        return "Temperature{mValue=" + mValue + ", mType=" + mType
+                + ", mName=" + mName + ", mStatus=" + mStatus + "}";
     }
 
-    /**
-     * Fill in Temperature members from a Parcel.
-     *
-     * @param p the parceled Temperature object.
-     */
-    public void readFromParcel(Parcel p) {
-        mValue = p.readFloat();
-        mType = p.readInt();
-        mName = p.readString();
-        mStatus = p.readInt();
+    @Override
+    public int hashCode() {
+        int hash = mName.hashCode();
+        hash = 31 * hash + Float.hashCode(mValue);
+        hash = 31 * hash + mType;
+        hash = 31 * hash + mStatus;
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof Temperature)) {
+            return false;
+        }
+        Temperature other = (Temperature) o;
+        return other.mValue == mValue && other.mType == mType
+                && other.mName.equals(mName) && other.mStatus == mStatus;
     }
 
     @Override
@@ -181,13 +192,18 @@ public final class Temperature implements Parcelable {
             new Parcelable.Creator<Temperature>() {
                 @Override
                 public Temperature createFromParcel(Parcel p) {
-                    return new Temperature(p);
+                    float value = p.readFloat();
+                    int type = p.readInt();
+                    String name = p.readString();
+                    int status = p.readInt();
+                    return new Temperature(value, type, name, status);
                 }
 
                 @Override
                 public Temperature[] newArray(int size) {
                     return new Temperature[size];
                 }
+
             };
 
     @Override
index 16d11ef..0381445 100644 (file)
@@ -24,6 +24,7 @@ import android.hardware.thermal.V1_1.IThermalCallback;
 import android.hardware.thermal.V2_0.IThermalChangedCallback;
 import android.hardware.thermal.V2_0.ThrottlingSeverity;
 import android.os.Binder;
+import android.os.CoolingDevice;
 import android.os.HwBinder;
 import android.os.IThermalEventListener;
 import android.os.IThermalService;
@@ -49,8 +50,10 @@ import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * This is a system service that listens to HAL thermal events and dispatch those to listeners.
@@ -93,8 +96,7 @@ public class ThermalManagerService extends SystemService {
     private ThermalHalWrapper mHalWrapper;
 
     /** Hal ready. */
-    @GuardedBy("mLock")
-    private boolean mHalReady;
+    private final AtomicBoolean mHalReady = new AtomicBoolean();
 
     /** Invalid throttling status */
     private static final int INVALID_THROTTLING = Integer.MIN_VALUE;
@@ -150,7 +152,7 @@ public class ThermalManagerService extends SystemService {
                 onTemperatureChanged(temperatures.get(i), false);
             }
             onTemperatureMapChangedLocked();
-            mHalReady = halConnected /* true */;
+            mHalReady.set(true);
         }
     }
 
@@ -298,20 +300,6 @@ public class ThermalManagerService extends SystemService {
         }
     }
 
-    private void dumpTemperaturesLocked(PrintWriter pw, String prefix,
-            Collection<Temperature> temperatures) {
-        for (Temperature t : temperatures) {
-            pw.print(prefix);
-            String out = String.format("Name: %s, Type: %d, Status: %d, Value: %f",
-                    t.getName(),
-                    t.getType(),
-                    t.getStatus(),
-                    t.getValue()
-            );
-            pw.println(out);
-        }
-    }
-
     @VisibleForTesting
     final IThermalService.Stub mService = new IThermalService.Stub() {
         @Override
@@ -324,7 +312,7 @@ public class ThermalManagerService extends SystemService {
                     if (!mThermalEventListeners.register(listener, null)) {
                         return false;
                     }
-                    if (mHalReady) {
+                    if (mHalReady.get()) {
                         // Notify its callback after new client registered.
                         postEventListenerCurrentTemperatures(listener, null);
                     }
@@ -346,7 +334,7 @@ public class ThermalManagerService extends SystemService {
                     if (!mThermalEventListeners.register(listener, new Integer(type))) {
                         return false;
                     }
-                    if (mHalReady) {
+                    if (mHalReady.get()) {
                         // Notify its callback after new client registered.
                         postEventListenerCurrentTemperatures(listener, new Integer(type));
                     }
@@ -377,7 +365,7 @@ public class ThermalManagerService extends SystemService {
                     android.Manifest.permission.DEVICE_POWER, null);
             final long token = Binder.clearCallingIdentity();
             try {
-                if (!mHalReady) {
+                if (!mHalReady.get()) {
                     return new ArrayList<>();
                 }
                 return mHalWrapper.getCurrentTemperatures(false, 0 /* not used */);
@@ -392,7 +380,7 @@ public class ThermalManagerService extends SystemService {
                     android.Manifest.permission.DEVICE_POWER, null);
             final long token = Binder.clearCallingIdentity();
             try {
-                if (!mHalReady) {
+                if (!mHalReady.get()) {
                     return new ArrayList<>();
                 }
                 return mHalWrapper.getCurrentTemperatures(true, type);
@@ -410,7 +398,7 @@ public class ThermalManagerService extends SystemService {
                     if (!mThermalStatusListeners.register(listener)) {
                         return false;
                     }
-                    if (mHalReady) {
+                    if (mHalReady.get()) {
                         // Notify its callback after new client registered.
                         postStatusListener(listener);
                     }
@@ -447,6 +435,43 @@ public class ThermalManagerService extends SystemService {
         }
 
         @Override
+        public List<CoolingDevice> getCurrentCoolingDevices() {
+            getContext().enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, null);
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (!mHalReady.get()) {
+                    return new ArrayList<>();
+                }
+                return mHalWrapper.getCurrentCoolingDevices(false, 0);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public List<CoolingDevice> getCurrentCoolingDevicesWithType(int type) {
+            getContext().enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, null);
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (!mHalReady.get()) {
+                    return new ArrayList<>();
+                }
+                return mHalWrapper.getCurrentCoolingDevices(true, type);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        private void dumpItemsLocked(PrintWriter pw, String prefix,
+                Collection<?> items) {
+            for (Iterator iterator = items.iterator(); iterator.hasNext();) {
+                pw.println(prefix + iterator.next().toString());
+            }
+        }
+
+        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
                 return;
@@ -461,17 +486,19 @@ public class ThermalManagerService extends SystemService {
                     mThermalStatusListeners.dump(pw, "\t");
                     pw.println("Thermal Status: " + mStatus);
                     pw.println("Cached temperatures:");
-                    dumpTemperaturesLocked(pw, "\t", mTemperatureMap.values());
-                    pw.println("HAL Ready: " + mHalReady);
-                    if (mHalReady) {
+                    dumpItemsLocked(pw, "\t", mTemperatureMap.values());
+                    pw.println("HAL Ready: " + mHalReady.get());
+                    if (mHalReady.get()) {
                         pw.println("HAL connection:");
                         mHalWrapper.dump(pw, "\t");
                         pw.println("Current temperatures from HAL:");
-                        dumpTemperaturesLocked(pw, "\t",
+                        dumpItemsLocked(pw, "\t",
                                 mHalWrapper.getCurrentTemperatures(false, 0));
+                        pw.println("Current cooling devices from HAL:");
+                        dumpItemsLocked(pw, "\t",
+                                mHalWrapper.getCurrentCoolingDevices(false, 0));
                     }
                 }
-
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -588,6 +615,9 @@ public class ThermalManagerService extends SystemService {
         protected abstract List<Temperature> getCurrentTemperatures(boolean shouldFilter,
                 int type);
 
+        protected abstract List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
+                int type);
+
         protected abstract boolean connectToHal();
 
         protected abstract void dump(PrintWriter pw, String prefix);
@@ -664,6 +694,42 @@ public class ThermalManagerService extends SystemService {
         }
 
         @Override
+        protected List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
+                int type) {
+            synchronized (mHalLock) {
+                List<CoolingDevice> ret = new ArrayList<>();
+                if (mThermalHal10 == null) {
+                    return ret;
+                }
+                try {
+                    mThermalHal10.getCoolingDevices((status, coolingDevices) -> {
+                        if (ThermalStatusCode.SUCCESS == status.code) {
+                            for (android.hardware.thermal.V1_0.CoolingDevice
+                                    coolingDevice : coolingDevices) {
+                                if (shouldFilter && type != coolingDevice.type) {
+                                    continue;
+                                }
+                                ret.add(new CoolingDevice(
+                                        (long) coolingDevice.currentValue,
+                                        coolingDevice.type,
+                                        coolingDevice.name));
+                            }
+                        } else {
+                            Slog.e(TAG,
+                                    "Couldn't get cooling device because of HAL error: "
+                                            + status.debugMessage);
+                        }
+
+                    });
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Couldn't getCurrentCoolingDevices, reconnecting...", e);
+                    connectToHal();
+                }
+                return ret;
+            }
+        }
+
+        @Override
         protected boolean connectToHal() {
             synchronized (mHalLock) {
                 try {
@@ -757,6 +823,42 @@ public class ThermalManagerService extends SystemService {
         }
 
         @Override
+        protected List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
+                int type) {
+            synchronized (mHalLock) {
+                List<CoolingDevice> ret = new ArrayList<>();
+                if (mThermalHal11 == null) {
+                    return ret;
+                }
+                try {
+                    mThermalHal11.getCoolingDevices((status, coolingDevices) -> {
+                        if (ThermalStatusCode.SUCCESS == status.code) {
+                            for (android.hardware.thermal.V1_0.CoolingDevice
+                                    coolingDevice : coolingDevices) {
+                                if (shouldFilter && type != coolingDevice.type) {
+                                    continue;
+                                }
+                                ret.add(new CoolingDevice(
+                                        (long) coolingDevice.currentValue,
+                                        coolingDevice.type,
+                                        coolingDevice.name));
+                            }
+                        } else {
+                            Slog.e(TAG,
+                                    "Couldn't get cooling device because of HAL error: "
+                                            + status.debugMessage);
+                        }
+
+                    });
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Couldn't getCurrentCoolingDevices, reconnecting...", e);
+                    connectToHal();
+                }
+                return ret;
+            }
+        }
+
+        @Override
         protected boolean connectToHal() {
             synchronized (mHalLock) {
                 try {
@@ -817,9 +919,7 @@ public class ThermalManagerService extends SystemService {
                 }
                 try {
                     mThermalHal20.getCurrentTemperatures(shouldFilter, type,
-                            (ThermalStatus status,
-                                    ArrayList<android.hardware.thermal.V2_0.Temperature>
-                                            temperatures) -> {
+                            (status, temperatures) -> {
                                 if (ThermalStatusCode.SUCCESS == status.code) {
                                     for (android.hardware.thermal.V2_0.Temperature
                                             temperature : temperatures) {
@@ -844,6 +944,39 @@ public class ThermalManagerService extends SystemService {
         }
 
         @Override
+        protected List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
+                int type) {
+            synchronized (mHalLock) {
+                List<CoolingDevice> ret = new ArrayList<>();
+                if (mThermalHal20 == null) {
+                    return ret;
+                }
+                try {
+                    mThermalHal20.getCurrentCoolingDevices(shouldFilter, type,
+                            (status, coolingDevices) -> {
+                                if (ThermalStatusCode.SUCCESS == status.code) {
+                                    for (android.hardware.thermal.V2_0.CoolingDevice
+                                            coolingDevice : coolingDevices) {
+                                        ret.add(new CoolingDevice(
+                                                coolingDevice.value, coolingDevice.type,
+                                                coolingDevice.name));
+                                    }
+                                } else {
+                                    Slog.e(TAG,
+                                            "Couldn't get cooling device because of HAL error: "
+                                                    + status.debugMessage);
+                                }
+
+                            });
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Couldn't getCurrentCoolingDevices, reconnecting...", e);
+                    connectToHal();
+                }
+                return ret;
+            }
+        }
+
+        @Override
         protected boolean connectToHal() {
             synchronized (mHalLock) {
                 try {
index 94d293e..27d5296 100644 (file)
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.os.CoolingDevice;
 import android.os.IBinder;
 import android.os.IPowerManager;
 import android.os.IThermalEventListener;
@@ -85,6 +86,8 @@ public class ThermalManagerServiceTest {
     private class ThermalHalFake extends ThermalHalWrapper {
         private static final int INIT_STATUS = Temperature.THROTTLING_NONE;
         private ArrayList<Temperature> mTemperatureList = new ArrayList<>();
+        private ArrayList<CoolingDevice> mCoolingDeviceList = new ArrayList<>();
+
         private Temperature mSkin1 = new Temperature(0, Temperature.TYPE_SKIN, "skin1",
                 INIT_STATUS);
         private Temperature mSkin2 = new Temperature(0, Temperature.TYPE_SKIN, "skin2",
@@ -93,17 +96,40 @@ public class ThermalManagerServiceTest {
                 INIT_STATUS);
         private Temperature mUsbPort = new Temperature(0, Temperature.TYPE_USB_PORT, "usbport",
                 INIT_STATUS);
+        private CoolingDevice mCpu = new CoolingDevice(0, CoolingDevice.TYPE_BATTERY, "cpu");
+        private CoolingDevice mGpu = new CoolingDevice(0, CoolingDevice.TYPE_BATTERY, "gpu");
 
         ThermalHalFake() {
             mTemperatureList.add(mSkin1);
             mTemperatureList.add(mSkin2);
             mTemperatureList.add(mBattery);
             mTemperatureList.add(mUsbPort);
+            mCoolingDeviceList.add(mCpu);
+            mCoolingDeviceList.add(mGpu);
         }
 
         @Override
         protected List<Temperature> getCurrentTemperatures(boolean shouldFilter, int type) {
-            return mTemperatureList;
+            List<Temperature> ret = new ArrayList<>();
+            for (Temperature temperature : mTemperatureList) {
+                if (shouldFilter && type != temperature.getType()) {
+                    continue;
+                }
+                ret.add(temperature);
+            }
+            return ret;
+        }
+
+        @Override
+        protected List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter, int type) {
+            List<CoolingDevice> ret = new ArrayList<>();
+            for (CoolingDevice cdev : mCoolingDeviceList) {
+                if (shouldFilter && type != cdev.getType()) {
+                    continue;
+                }
+                ret.add(cdev);
+            }
+            return ret;
         }
 
         @Override
@@ -117,8 +143,10 @@ public class ThermalManagerServiceTest {
         }
     }
 
-    private void assertTemperatureEquals(List<Temperature> expected, List<Temperature> value) {
-        assertEquals(new HashSet<>(expected), new HashSet<>(value));
+    private void assertListEqualsIgnoringOrder(List<?> actual, List<?> expected) {
+        HashSet<?> actualSet = new HashSet<>(actual);
+        HashSet<?> expectedSet = new HashSet<>(expected);
+        assertEquals(expectedSet, actualSet);
     }
 
     @Before
@@ -148,13 +176,14 @@ public class ThermalManagerServiceTest {
         ArgumentCaptor<Temperature> captor = ArgumentCaptor.forClass(Temperature.class);
         verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
                 .times(4)).notifyThrottling(captor.capture());
-        assertTemperatureEquals(mFakeHal.mTemperatureList, captor.getAllValues());
+        assertListEqualsIgnoringOrder(mFakeHal.mTemperatureList, captor.getAllValues());
         verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
                 .times(1)).onStatusChange(Temperature.THROTTLING_NONE);
         captor = ArgumentCaptor.forClass(Temperature.class);
         verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
                 .times(2)).notifyThrottling(captor.capture());
-        assertTemperatureEquals(new ArrayList<>(Arrays.asList(mFakeHal.mSkin1, mFakeHal.mSkin2)),
+        assertListEqualsIgnoringOrder(
+                new ArrayList<>(Arrays.asList(mFakeHal.mSkin1, mFakeHal.mSkin2)),
                 captor.getAllValues());
         verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
                 .times(1)).onStatusChange(Temperature.THROTTLING_NONE);
@@ -185,7 +214,7 @@ public class ThermalManagerServiceTest {
         ArgumentCaptor<Temperature> captor = ArgumentCaptor.forClass(Temperature.class);
         verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
                 .times(4)).notifyThrottling(captor.capture());
-        assertTemperatureEquals(mFakeHal.mTemperatureList, captor.getAllValues());
+        assertListEqualsIgnoringOrder(mFakeHal.mTemperatureList, captor.getAllValues());
         verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
                 .times(1)).onStatusChange(Temperature.THROTTLING_NONE);
         // Register new callbacks and verify old ones are not called (remained same) while new
@@ -200,7 +229,8 @@ public class ThermalManagerServiceTest {
         captor = ArgumentCaptor.forClass(Temperature.class);
         verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
                 .times(2)).notifyThrottling(captor.capture());
-        assertTemperatureEquals(new ArrayList<>(Arrays.asList(mFakeHal.mSkin1, mFakeHal.mSkin2)),
+        assertListEqualsIgnoringOrder(
+                new ArrayList<>(Arrays.asList(mFakeHal.mSkin1, mFakeHal.mSkin2)),
                 captor.getAllValues());
         verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
                 .times(1)).onStatusChange(Temperature.THROTTLING_NONE);
@@ -260,9 +290,9 @@ public class ThermalManagerServiceTest {
 
     @Test
     public void testGetCurrentTemperatures() throws RemoteException {
-        assertTemperatureEquals(mFakeHal.getCurrentTemperatures(false, 0),
+        assertListEqualsIgnoringOrder(mFakeHal.getCurrentTemperatures(false, 0),
                 mService.mService.getCurrentTemperatures());
-        assertTemperatureEquals(mFakeHal.getCurrentTemperatures(true, Temperature.TYPE_SKIN),
+        assertListEqualsIgnoringOrder(mFakeHal.getCurrentTemperatures(true, Temperature.TYPE_SKIN),
                 mService.mService.getCurrentTemperaturesWithType(Temperature.TYPE_SKIN));
     }
 
@@ -300,4 +330,16 @@ public class ThermalManagerServiceTest {
                 mService.mService.getCurrentTemperaturesWithType(Temperature.TYPE_SKIN).size());
         assertEquals(Temperature.THROTTLING_NONE, mService.mService.getCurrentThermalStatus());
     }
+
+    @Test
+    public void testGetCurrentCoolingDevices() throws RemoteException {
+        assertListEqualsIgnoringOrder(mFakeHal.getCurrentCoolingDevices(false, 0),
+                mService.mService.getCurrentCoolingDevices());
+        assertListEqualsIgnoringOrder(
+                mFakeHal.getCurrentCoolingDevices(false, CoolingDevice.TYPE_BATTERY),
+                mService.mService.getCurrentCoolingDevices());
+        assertListEqualsIgnoringOrder(
+                mFakeHal.getCurrentCoolingDevices(true, CoolingDevice.TYPE_CPU),
+                mService.mService.getCurrentCoolingDevicesWithType(CoolingDevice.TYPE_CPU));
+    }
 }