diff options
| author | 2024-11-22 19:48:48 +0000 | |
|---|---|---|
| committer | 2024-11-22 19:48:48 +0000 | |
| commit | 025d338f7778047a412662aff76c123a04d1519a (patch) | |
| tree | 92be6898a187107862d10a420168366d6abe0cf0 | |
| parent | 51c1d767b887e6e75f7ed2810499371d46f03eb4 (diff) | |
| parent | 2a6b5a929b9b7cfbe4d173cdb17c9d7f64cbf887 (diff) | |
Merge "Add support for calculation window size and tids" into main
10 files changed, 388 insertions, 216 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 3af8e7e17dbd..55e1aeccd0fd 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -33612,9 +33612,14 @@ package android.os { @FlaggedApi("android.os.cpu_gpu_headrooms") public final class CpuHeadroomParams { ctor public CpuHeadroomParams(); method public int getCalculationType(); + method @IntRange(from=android.os.CpuHeadroomParams.CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN, to=android.os.CpuHeadroomParams.CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) public long getCalculationWindowMillis(); method public void setCalculationType(int); + method public void setCalculationWindowMillis(@IntRange(from=android.os.CpuHeadroomParams.CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN, to=android.os.CpuHeadroomParams.CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) int); + method public void setTids(@NonNull int...); field public static final int CPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; // 0x1 field public static final int CPU_HEADROOM_CALCULATION_TYPE_MIN = 0; // 0x0 + field public static final int CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX = 10000; // 0x2710 + field public static final int CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN = 50; // 0x32 } public final class CpuUsageInfo implements android.os.Parcelable { @@ -33867,9 +33872,13 @@ package android.os { @FlaggedApi("android.os.cpu_gpu_headrooms") public final class GpuHeadroomParams { ctor public GpuHeadroomParams(); method public int getCalculationType(); + method @IntRange(from=android.os.GpuHeadroomParams.GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN, to=android.os.GpuHeadroomParams.GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) public int getCalculationWindowMillis(); method public void setCalculationType(int); + method public void setCalculationWindowMillis(@IntRange(from=android.os.GpuHeadroomParams.GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN, to=android.os.GpuHeadroomParams.GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) int); field public static final int GPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; // 0x1 field public static final int GPU_HEADROOM_CALCULATION_TYPE_MIN = 0; // 0x0 + field public static final int GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX = 10000; // 0x2710 + field public static final int GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN = 50; // 0x32 } public class Handler { diff --git a/core/java/android/os/CpuHeadroomParams.java b/core/java/android/os/CpuHeadroomParams.java index f0d4f7d8737f..8e78b7e355f9 100644 --- a/core/java/android/os/CpuHeadroomParams.java +++ b/core/java/android/os/CpuHeadroomParams.java @@ -18,10 +18,13 @@ package android.os; import android.annotation.FlaggedApi; import android.annotation.IntDef; +import android.annotation.IntRange; +import android.annotation.NonNull; import android.os.health.SystemHealthManager; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; /** * Headroom request params used by {@link SystemHealthManager#getCpuHeadroom(CpuHeadroomParams)}. @@ -54,6 +57,16 @@ public final class CpuHeadroomParams { public static final int CPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; /** + * Minimum CPU headroom calculation window size. + */ + public static final int CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN = 50; + + /** + * Maximum CPU headroom calculation window size. + */ + public static final int CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX = 10000; + + /** * Sets the headroom calculation type. * <p> * @@ -83,6 +96,63 @@ public final class CpuHeadroomParams { } /** + * Sets the headroom calculation window size in milliseconds. + * <p> + * + * @param windowMillis the window size in milliseconds, ranged from + * [{@link #CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN}, + * {@link #CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX}]. The smaller + * the value, the larger fluctuation in value should be expected. The + * default value can be retrieved from the + * {@link #getCalculationWindowMillis}. The device will try to use the + * closest feasible window size to this param. + * @throws IllegalArgumentException if the window size is not in allowed range. + */ + public void setCalculationWindowMillis( + @IntRange(from = CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN, to = + CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) int windowMillis) { + if (windowMillis < CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN + || windowMillis > CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) { + throw new IllegalArgumentException("Invalid calculation window: " + windowMillis); + } + mInternal.calculationWindowMillis = windowMillis; + } + + /** + * Gets the headroom calculation window size in milliseconds. + * <p> + * This will return the default value chosen by the device if not set. + */ + public @IntRange(from = CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN, to = + CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) long getCalculationWindowMillis() { + return mInternal.calculationWindowMillis; + } + + /** + * Sets the thread TIDs to track. + * <p> + * The TIDs should belong to the same of the process that will the headroom call. And they + * should not have different core affinity. + * <p> + * If not set, the headroom will be based on the PID of the process making the call. + * + * @param tids non-empty list of TIDs, maximum 5. + * @throws IllegalArgumentException if the list size is not in allowed range or TID is not + * positive. + */ + public void setTids(@NonNull int... tids) { + if (tids.length == 0 || tids.length > 5) { + throw new IllegalArgumentException("Invalid number of TIDs: " + tids.length); + } + for (int tid : tids) { + if (tid <= 0) { + throw new IllegalArgumentException("Invalid TID: " + tid); + } + } + mInternal.tids = Arrays.copyOf(tids, tids.length); + } + + /** * @hide */ public CpuHeadroomParamsInternal getInternal() { diff --git a/core/java/android/os/CpuHeadroomParamsInternal.aidl b/core/java/android/os/CpuHeadroomParamsInternal.aidl index 6cc4699a809e..d572f965579b 100644 --- a/core/java/android/os/CpuHeadroomParamsInternal.aidl +++ b/core/java/android/os/CpuHeadroomParamsInternal.aidl @@ -25,6 +25,8 @@ import android.hardware.power.CpuHeadroomParams; @JavaDerive(equals = true, toString = true) parcelable CpuHeadroomParamsInternal { boolean usesDeviceHeadroom = false; + int[] tids; + int calculationWindowMillis = 1000; CpuHeadroomParams.CalculationType calculationType = CpuHeadroomParams.CalculationType.MIN; CpuHeadroomParams.SelectionType selectionType = CpuHeadroomParams.SelectionType.ALL; } diff --git a/core/java/android/os/GpuHeadroomParams.java b/core/java/android/os/GpuHeadroomParams.java index efb2a28ad2b5..4dc98264e57b 100644 --- a/core/java/android/os/GpuHeadroomParams.java +++ b/core/java/android/os/GpuHeadroomParams.java @@ -18,6 +18,7 @@ package android.os; import android.annotation.FlaggedApi; import android.annotation.IntDef; +import android.annotation.IntRange; import android.os.health.SystemHealthManager; import java.lang.annotation.Retention; @@ -54,6 +55,16 @@ public final class GpuHeadroomParams { public static final int GPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; /** + * Minimum GPU headroom calculation window size. + */ + public static final int GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN = 50; + + /** + * Maximum GPU headroom calculation window size. + */ + public static final int GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX = 10000; + + /** * Sets the headroom calculation type. * <p> * @@ -83,6 +94,39 @@ public final class GpuHeadroomParams { } /** + * Sets the headroom calculation window size in milliseconds. + * <p> + * + * @param windowMillis the window size in milliseconds, ranged from + * [{@link #GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN}, + * {@link #GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX}]. The smaller + * the value, the larger fluctuation in value should be expected. The + * default value can be retrieved from the + * {@link #getCalculationWindowMillis}. If the device will try to use the + * closest feasible window size to this param. + * @throws IllegalArgumentException if the window is invalid. + */ + public void setCalculationWindowMillis( + @IntRange(from = GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN, to = + GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) int windowMillis) { + if (windowMillis < GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN + || windowMillis > GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) { + throw new IllegalArgumentException("Invalid calculation window: " + windowMillis); + } + mInternal.calculationWindowMillis = windowMillis; + } + + /** + * Gets the headroom calculation window size in milliseconds. + * <p> + * This will return the default value chosen by the device if not set. + */ + public @IntRange(from = GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN, to = + GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) int getCalculationWindowMillis() { + return mInternal.calculationWindowMillis; + } + + /** * @hide */ public GpuHeadroomParamsInternal getInternal() { diff --git a/core/java/android/os/GpuHeadroomParamsInternal.aidl b/core/java/android/os/GpuHeadroomParamsInternal.aidl index 20309e7673f2..40d5d8e409ef 100644 --- a/core/java/android/os/GpuHeadroomParamsInternal.aidl +++ b/core/java/android/os/GpuHeadroomParamsInternal.aidl @@ -24,5 +24,6 @@ import android.hardware.power.GpuHeadroomParams; */ @JavaDerive(equals = true, toString = true) parcelable GpuHeadroomParamsInternal { + int calculationWindowMillis = 1000; GpuHeadroomParams.CalculationType calculationType = GpuHeadroomParams.CalculationType.MIN; } diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl index a043da9b7a36..f1936b5e0ff9 100644 --- a/core/java/android/os/IHintManager.aidl +++ b/core/java/android/os/IHintManager.aidl @@ -21,7 +21,9 @@ import android.os.CpuHeadroomParamsInternal; import android.os.GpuHeadroomParamsInternal; import android.os.IHintSession; import android.os.SessionCreationConfig; +import android.hardware.power.CpuHeadroomResult; import android.hardware.power.ChannelConfig; +import android.hardware.power.GpuHeadroomResult; import android.hardware.power.SessionConfig; import android.hardware.power.SessionTag; @@ -53,9 +55,9 @@ interface IHintManager { */ @nullable ChannelConfig getSessionChannel(in IBinder token); oneway void closeSessionChannel(); - float[] getCpuHeadroom(in CpuHeadroomParamsInternal params); + @nullable CpuHeadroomResult getCpuHeadroom(in CpuHeadroomParamsInternal params); long getCpuHeadroomMinIntervalMillis(); - float getGpuHeadroom(in GpuHeadroomParamsInternal params); + @nullable GpuHeadroomResult getGpuHeadroom(in GpuHeadroomParamsInternal params); long getGpuHeadroomMinIntervalMillis(); /** diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java index 4db9bc333e2b..cd79e416531a 100644 --- a/core/java/android/os/health/SystemHealthManager.java +++ b/core/java/android/os/health/SystemHealthManager.java @@ -23,6 +23,8 @@ import android.annotation.Nullable; import android.annotation.SystemService; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.hardware.power.CpuHeadroomResult; +import android.hardware.power.GpuHeadroomResult; import android.os.BatteryStats; import android.os.Build; import android.os.Bundle; @@ -110,15 +112,16 @@ public class SystemHealthManager { } /** - * Provides an estimate of global available CPU headroom of the calling thread. + * Provides an estimate of global available CPU headroom. * <p> * * @param params params to customize the CPU headroom calculation, null to use default params. - * @return a single value a {@code Float.NaN} if it's temporarily unavailable. + * @return a single value headroom or a {@code Float.NaN} if it's temporarily unavailable. * A valid value is ranged from [0, 100], where 0 indicates no more CPU resources can be * granted. - * @throws UnsupportedOperationException if the API is unsupported or the request params can't - * be served. + * @throws UnsupportedOperationException if the API is unsupported. + * @throws SecurityException if the TIDs of the params don't belong to the same process. + * @throws IllegalStateException if the TIDs of the params don't have the same affinity setting. */ @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS) public @FloatRange(from = 0f, to = 100f) float getCpuHeadroom( @@ -127,8 +130,12 @@ public class SystemHealthManager { throw new UnsupportedOperationException(); } try { - return mHintManager.getCpuHeadroom( - params != null ? params.getInternal() : new CpuHeadroomParamsInternal())[0]; + final CpuHeadroomResult ret = mHintManager.getCpuHeadroom( + params != null ? params.getInternal() : new CpuHeadroomParamsInternal()); + if (ret == null || ret.getTag() != CpuHeadroomResult.globalHeadroom) { + return Float.NaN; + } + return ret.getGlobalHeadroom(); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -144,8 +151,7 @@ public class SystemHealthManager { * @return a single value headroom or a {@code Float.NaN} if it's temporarily unavailable. * A valid value is ranged from [0, 100], where 0 indicates no more GPU resources can be * granted. - * @throws UnsupportedOperationException if the API is unsupported or the request params can't - * be served. + * @throws UnsupportedOperationException if the API is unsupported. */ @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS) public @FloatRange(from = 0f, to = 100f) float getGpuHeadroom( @@ -154,8 +160,12 @@ public class SystemHealthManager { throw new UnsupportedOperationException(); } try { - return mHintManager.getGpuHeadroom( + final GpuHeadroomResult ret = mHintManager.getGpuHeadroom( params != null ? params.getInternal() : new GpuHeadroomParamsInternal()); + if (ret == null || ret.getTag() != GpuHeadroomResult.globalHeadroom) { + return Float.NaN; + } + return ret.getGlobalHeadroom(); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp index c5fb80840b84..b00658052bde 100644 --- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp @@ -73,13 +73,13 @@ public: MOCK_METHOD(ScopedAStatus, closeSessionChannel, (), (override)); MOCK_METHOD(ScopedAStatus, getCpuHeadroom, (const ::aidl::android::os::CpuHeadroomParamsInternal& in_params, - std::vector<float>* _aidl_return), + std::optional<hal::CpuHeadroomResult>* _aidl_return), (override)); MOCK_METHOD(ScopedAStatus, getCpuHeadroomMinIntervalMillis, (int64_t* _aidl_return), (override)); MOCK_METHOD(ScopedAStatus, getGpuHeadroom, (const ::aidl::android::os::GpuHeadroomParamsInternal& in_params, - float* _aidl_return), + std::optional<hal::GpuHeadroomResult>* _aidl_return), (override)); MOCK_METHOD(ScopedAStatus, getGpuHeadroomMinIntervalMillis, (int64_t* _aidl_return), (override)); diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java index 71f67d82dbec..aba15c83f907 100644 --- a/services/core/java/com/android/server/power/hint/HintManagerService.java +++ b/services/core/java/com/android/server/power/hint/HintManagerService.java @@ -34,7 +34,9 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.hardware.power.ChannelConfig; import android.hardware.power.CpuHeadroomParams; +import android.hardware.power.CpuHeadroomResult; import android.hardware.power.GpuHeadroomParams; +import android.hardware.power.GpuHeadroomResult; import android.hardware.power.IPower; import android.hardware.power.SessionConfig; import android.hardware.power.SessionTag; @@ -79,6 +81,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; @@ -96,10 +99,10 @@ public final class HintManagerService extends SystemService { private static final int EVENT_CLEAN_UP_UID = 3; @VisibleForTesting static final int CLEAN_UP_UID_DELAY_MILLIS = 1000; + // The minimum interval between the headroom calls as rate limiting. private static final int DEFAULT_GPU_HEADROOM_INTERVAL_MILLIS = 1000; private static final int DEFAULT_CPU_HEADROOM_INTERVAL_MILLIS = 1000; private static final int HEADROOM_INTERVAL_UNSUPPORTED = -1; - @VisibleForTesting static final int DEFAULT_HEADROOM_PID = -1; @VisibleForTesting final long mHintSessionPreferredRate; @@ -184,73 +187,77 @@ public final class HintManagerService extends SystemService { private static final String PROPERTY_SF_ENABLE_CPU_HINT = "debug.sf.enable_adpf_cpu_hint"; private static final String PROPERTY_HWUI_ENABLE_HINT_MANAGER = "debug.hwui.use_hint_manager"; private static final String PROPERTY_USE_HAL_HEADROOMS = "persist.hms.use_hal_headrooms"; + private static final String PROPERTY_CHECK_HEADROOM_TID = "persist.hms.check_headroom_tid"; private Boolean mFMQUsesIntegratedEventFlag = false; private final Object mCpuHeadroomLock = new Object(); - private static class CpuHeadroomCacheItem { - long mExpiredTimeMillis; - CpuHeadroomParamsInternal mParams; - float[] mHeadroom; - long mPid; - CpuHeadroomCacheItem(long expiredTimeMillis, CpuHeadroomParamsInternal params, - float[] headroom, long pid) { - mExpiredTimeMillis = expiredTimeMillis; - mParams = params; - mPid = pid; - mHeadroom = headroom; - } + // this cache tracks the expiration time of the items and performs cleanup on lookup + private static class HeadroomCache<K, V> { + final List<HeadroomCacheItem> mItemList; + final Map<K, HeadroomCacheItem> mKeyItemMap; + final long mItemExpDurationMillis; + + class HeadroomCacheItem { + long mExpTime; + K mKey; + V mValue; - private boolean match(CpuHeadroomParamsInternal params, long pid) { - if (mParams == null && params == null) return true; - if (mParams != null) { - return mParams.equals(params) && pid == mPid; + HeadroomCacheItem(K k, V v) { + mExpTime = System.currentTimeMillis() + mItemExpDurationMillis; + mKey = k; + mValue = v; } - return false; - } - private boolean isExpired() { - return System.currentTimeMillis() > mExpiredTimeMillis; + boolean isExpired() { + return mExpTime <= System.currentTimeMillis(); + } } - } - - @GuardedBy("mCpuHeadroomLock") - private final List<CpuHeadroomCacheItem> mCpuHeadroomCache; - private final long mCpuHeadroomIntervalMillis; - - private final Object mGpuHeadroomLock = new Object(); - private static class GpuHeadroomCacheItem { - long mExpiredTimeMillis; - GpuHeadroomParamsInternal mParams; - float mHeadroom; - - GpuHeadroomCacheItem(long expiredTimeMillis, GpuHeadroomParamsInternal params, - float headroom) { - mExpiredTimeMillis = expiredTimeMillis; - mParams = params; - mHeadroom = headroom; + void add(K key, V value) { + if (mKeyItemMap.containsKey(key)) { + final HeadroomCacheItem item = mKeyItemMap.get(key); + mItemList.remove(item); + } + final HeadroomCacheItem item = new HeadroomCacheItem(key, value); + mItemList.add(item); + mKeyItemMap.put(key, item); } - private boolean match(GpuHeadroomParamsInternal params) { - if (mParams == null && params == null) return true; - if (mParams != null) { - return mParams.equals(params); + V get(K key) { + while (!mItemList.isEmpty() && mItemList.getFirst().isExpired()) { + mKeyItemMap.remove(mItemList.removeFirst().mKey); } - return false; + final HeadroomCacheItem item = mKeyItemMap.get(key); + if (item == null) { + return null; + } + return item.mValue; } - private boolean isExpired() { - return System.currentTimeMillis() > mExpiredTimeMillis; + HeadroomCache(int size, long expDurationMillis) { + mItemList = new LinkedList<>(); + mKeyItemMap = new ArrayMap<>(size); + mItemExpDurationMillis = expDurationMillis; } } + @GuardedBy("mCpuHeadroomLock") + private final HeadroomCache<CpuHeadroomParams, CpuHeadroomResult> mCpuHeadroomCache; + private final long mCpuHeadroomIntervalMillis; + + private final Object mGpuHeadroomLock = new Object(); + @GuardedBy("mGpuHeadroomLock") - private final List<GpuHeadroomCacheItem> mGpuHeadroomCache; + private final HeadroomCache<GpuHeadroomParams, GpuHeadroomResult> mGpuHeadroomCache; private final long mGpuHeadroomIntervalMillis; + // these are set to default values in CpuHeadroomParamsInternal and GpuHeadroomParamsInternal + private final int mDefaultCpuHeadroomCalculationWindowMillis; + private final int mDefaultGpuHeadroomCalculationWindowMillis; + @VisibleForTesting final IHintManager.Stub mService = new BinderService(); @@ -303,26 +310,31 @@ public final class HintManagerService extends SystemService { } } mCpuHeadroomIntervalMillis = cpuHeadroomIntervalMillis; + mDefaultCpuHeadroomCalculationWindowMillis = + new CpuHeadroomParamsInternal().calculationWindowMillis; + mDefaultGpuHeadroomCalculationWindowMillis = + new GpuHeadroomParamsInternal().calculationWindowMillis; mGpuHeadroomIntervalMillis = gpuHeadroomIntervalMillis; if (mCpuHeadroomIntervalMillis > 0) { - mCpuHeadroomCache = new ArrayList<>(4); + mCpuHeadroomCache = new HeadroomCache<>(2, mCpuHeadroomIntervalMillis); } else { mCpuHeadroomCache = null; } if (mGpuHeadroomIntervalMillis > 0) { - mGpuHeadroomCache = new ArrayList<>(2); + mGpuHeadroomCache = new HeadroomCache<>(2, mGpuHeadroomIntervalMillis); } else { mGpuHeadroomCache = null; } } private long checkCpuHeadroomSupport() { + final CpuHeadroomParams params = new CpuHeadroomParams(); + params.tids = new int[]{Process.myPid()}; try { synchronized (mCpuHeadroomLock) { - final CpuHeadroomParams defaultParams = new CpuHeadroomParams(); - defaultParams.pid = Process.myPid(); - float[] ret = mPowerHal.getCpuHeadroom(defaultParams); - if (ret != null && ret.length > 0) { + final CpuHeadroomResult ret = mPowerHal.getCpuHeadroom(params); + if (ret != null && ret.getTag() == CpuHeadroomResult.globalHeadroom + && !Float.isNaN(ret.getGlobalHeadroom())) { return Math.max( DEFAULT_CPU_HEADROOM_INTERVAL_MILLIS, mPowerHal.getCpuHeadroomMinIntervalMillis()); @@ -330,27 +342,29 @@ public final class HintManagerService extends SystemService { } } catch (UnsupportedOperationException e) { - Slog.w(TAG, "getCpuHeadroom HAL API is not supported", e); + Slog.w(TAG, "getCpuHeadroom HAL API is not supported, params: " + params, e); } catch (RemoteException e) { - Slog.e(TAG, "getCpuHeadroom HAL API fails, disabling the API", e); + Slog.e(TAG, "getCpuHeadroom HAL API fails, disabling the API, params: " + params, e); } return HEADROOM_INTERVAL_UNSUPPORTED; } private long checkGpuHeadroomSupport() { + final GpuHeadroomParams params = new GpuHeadroomParams(); try { synchronized (mGpuHeadroomLock) { - float ret = mPowerHal.getGpuHeadroom(new GpuHeadroomParams()); - if (!Float.isNaN(ret)) { + final GpuHeadroomResult ret = mPowerHal.getGpuHeadroom(params); + if (ret != null && ret.getTag() == GpuHeadroomResult.globalHeadroom && !Float.isNaN( + ret.getGlobalHeadroom())) { return Math.max( DEFAULT_GPU_HEADROOM_INTERVAL_MILLIS, mPowerHal.getGpuHeadroomMinIntervalMillis()); } } } catch (UnsupportedOperationException e) { - Slog.w(TAG, "getGpuHeadroom HAL API is not supported", e); + Slog.w(TAG, "getGpuHeadroom HAL API is not supported, params: " + params, e); } catch (RemoteException e) { - Slog.e(TAG, "getGpuHeadroom HAL API fails, disabling the API", e); + Slog.e(TAG, "getGpuHeadroom HAL API fails, disabling the API, params: " + params, e); } return HEADROOM_INTERVAL_UNSUPPORTED; } @@ -1445,109 +1459,98 @@ public final class HintManagerService extends SystemService { } @Override - public float[] getCpuHeadroom(@Nullable CpuHeadroomParamsInternal params) { + public CpuHeadroomResult getCpuHeadroom(@NonNull CpuHeadroomParamsInternal params) { if (mCpuHeadroomIntervalMillis <= 0) { throw new UnsupportedOperationException(); } - CpuHeadroomParams halParams = new CpuHeadroomParams(); - halParams.pid = Binder.getCallingPid(); - if (params != null) { - halParams.calculationType = params.calculationType; - halParams.selectionType = params.selectionType; - if (params.usesDeviceHeadroom) { - halParams.pid = DEFAULT_HEADROOM_PID; - } - } - synchronized (mCpuHeadroomLock) { - while (!mCpuHeadroomCache.isEmpty()) { - if (mCpuHeadroomCache.getFirst().isExpired()) { - mCpuHeadroomCache.removeFirst(); - } else { - break; + final CpuHeadroomParams halParams = new CpuHeadroomParams(); + halParams.tids = new int[]{Binder.getCallingPid()}; + halParams.calculationType = params.calculationType; + halParams.calculationWindowMillis = params.calculationWindowMillis; + halParams.selectionType = params.selectionType; + if (params.usesDeviceHeadroom) { + halParams.tids = new int[]{}; + } else if (params.tids != null && params.tids.length > 0) { + if (params.tids.length > 5) { + throw new IllegalArgumentException( + "More than 5 TIDs is requested: " + params.tids.length); + } + if (SystemProperties.getBoolean(PROPERTY_CHECK_HEADROOM_TID, true)) { + final int tgid = Process.getThreadGroupLeader(Binder.getCallingPid()); + for (int tid : params.tids) { + if (Process.getThreadGroupLeader(tid) != tgid) { + throw new SecurityException("TID " + tid + + " doesn't belong to the calling process with pid " + + tgid); + } } } - for (int i = 0; i < mCpuHeadroomCache.size(); ++i) { - final CpuHeadroomCacheItem item = mCpuHeadroomCache.get(i); - if (item.match(params, halParams.pid)) { - item.mExpiredTimeMillis = - System.currentTimeMillis() + mCpuHeadroomIntervalMillis; - mCpuHeadroomCache.remove(i); - mCpuHeadroomCache.add(item); - return item.mHeadroom; - } + halParams.tids = params.tids; + } + if (halParams.calculationWindowMillis + == mDefaultCpuHeadroomCalculationWindowMillis) { + synchronized (mCpuHeadroomLock) { + final CpuHeadroomResult res = mCpuHeadroomCache.get(halParams); + if (res != null) return res; } } // return from HAL directly try { - float[] headroom = mPowerHal.getCpuHeadroom(halParams); - if (headroom == null || headroom.length == 0) { - Slog.wtf(TAG, - "CPU headroom from Power HAL is invalid: " + Arrays.toString(headroom)); - return new float[]{Float.NaN}; - } - synchronized (mCpuHeadroomLock) { - mCpuHeadroomCache.add(new CpuHeadroomCacheItem( - System.currentTimeMillis() + mCpuHeadroomIntervalMillis, - params, headroom, halParams.pid - )); + final CpuHeadroomResult result = mPowerHal.getCpuHeadroom(halParams); + if (result == null) { + Slog.wtf(TAG, "CPU headroom from Power HAL is invalid"); + return null; + } + if (halParams.calculationWindowMillis + == mDefaultCpuHeadroomCalculationWindowMillis) { + synchronized (mCpuHeadroomLock) { + mCpuHeadroomCache.add(halParams, result); + } } - return headroom; - + return result; } catch (RemoteException e) { - return new float[]{Float.NaN}; + Slog.e(TAG, "Failed to get CPU headroom from Power HAL", e); + return null; } } @Override - public float getGpuHeadroom(@Nullable GpuHeadroomParamsInternal params) { + public GpuHeadroomResult getGpuHeadroom(@NonNull GpuHeadroomParamsInternal params) { if (mGpuHeadroomIntervalMillis <= 0) { throw new UnsupportedOperationException(); } - GpuHeadroomParams halParams = new GpuHeadroomParams(); - if (params != null) { - halParams.calculationType = params.calculationType; - } - synchronized (mGpuHeadroomLock) { - while (!mGpuHeadroomCache.isEmpty()) { - if (mGpuHeadroomCache.getFirst().isExpired()) { - mGpuHeadroomCache.removeFirst(); - } else { - break; - } - } - for (int i = 0; i < mGpuHeadroomCache.size(); ++i) { - final GpuHeadroomCacheItem item = mGpuHeadroomCache.get(i); - if (item.match(params)) { - item.mExpiredTimeMillis = - System.currentTimeMillis() + mGpuHeadroomIntervalMillis; - mGpuHeadroomCache.remove(i); - mGpuHeadroomCache.add(item); - return item.mHeadroom; - } + final GpuHeadroomParams halParams = new GpuHeadroomParams(); + halParams.calculationType = params.calculationType; + halParams.calculationWindowMillis = params.calculationWindowMillis; + if (halParams.calculationWindowMillis + == mDefaultGpuHeadroomCalculationWindowMillis) { + synchronized (mGpuHeadroomLock) { + final GpuHeadroomResult res = mGpuHeadroomCache.get(halParams); + if (res != null) return res; } } // return from HAL directly try { - float headroom = mPowerHal.getGpuHeadroom(halParams); - if (Float.isNaN(headroom)) { - Slog.wtf(TAG, - "GPU headroom from Power HAL is NaN"); - return Float.NaN; - } - synchronized (mGpuHeadroomLock) { - mGpuHeadroomCache.add(new GpuHeadroomCacheItem( - System.currentTimeMillis() + mGpuHeadroomIntervalMillis, - params, headroom - )); + final GpuHeadroomResult headroom = mPowerHal.getGpuHeadroom(halParams); + if (headroom == null) { + Slog.wtf(TAG, "GPU headroom from Power HAL is invalid"); + return null; + } + if (halParams.calculationWindowMillis + == mDefaultGpuHeadroomCalculationWindowMillis) { + synchronized (mGpuHeadroomLock) { + mGpuHeadroomCache.add(halParams, headroom); + } } return headroom; } catch (RemoteException e) { - return Float.NaN; + Slog.e(TAG, "Failed to get GPU headroom from Power HAL", e); + return null; } } @Override - public long getCpuHeadroomMinIntervalMillis() throws RemoteException { + public long getCpuHeadroomMinIntervalMillis() { if (mCpuHeadroomIntervalMillis <= 0) { throw new UnsupportedOperationException(); } @@ -1555,7 +1558,7 @@ public final class HintManagerService extends SystemService { } @Override - public long getGpuHeadroomMinIntervalMillis() throws RemoteException { + public long getGpuHeadroomMinIntervalMillis() { if (mGpuHeadroomIntervalMillis <= 0) { throw new UnsupportedOperationException(); } @@ -1591,17 +1594,23 @@ public final class HintManagerService extends SystemService { CpuHeadroomParamsInternal params = new CpuHeadroomParamsInternal(); params.selectionType = CpuHeadroomParams.SelectionType.ALL; params.usesDeviceHeadroom = true; - pw.println("CPU headroom: " + Arrays.toString(getCpuHeadroom(params))); + CpuHeadroomResult ret = getCpuHeadroom(params); + pw.println("CPU headroom: " + (ret == null ? "N/A" : ret.getGlobalHeadroom())); params = new CpuHeadroomParamsInternal(); params.selectionType = CpuHeadroomParams.SelectionType.PER_CORE; params.usesDeviceHeadroom = true; - pw.println("CPU headroom per core: " + Arrays.toString(getCpuHeadroom(params))); + ret = getCpuHeadroom(params); + pw.println("CPU headroom per core: " + (ret == null ? "N/A" + : Arrays.toString(ret.getPerCoreHeadroom()))); } catch (Exception e) { + Slog.d(TAG, "Failed to dump CPU headroom", e); pw.println("CPU headroom: N/A"); } try { - pw.println("GPU headroom: " + getGpuHeadroom(null)); + GpuHeadroomResult ret = getGpuHeadroom(new GpuHeadroomParamsInternal()); + pw.println("GPU headroom: " + (ret == null ? "N/A" : ret.getGlobalHeadroom())); } catch (Exception e) { + Slog.d(TAG, "Failed to dump GPU headroom", e); pw.println("GPU headroom: N/A"); } } diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java index e631cb66eaf7..313c01d5ce58 100644 --- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java +++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java @@ -18,7 +18,6 @@ package com.android.server.power.hint; import static com.android.server.power.hint.HintManagerService.CLEAN_UP_UID_DELAY_MILLIS; -import static com.android.server.power.hint.HintManagerService.DEFAULT_HEADROOM_PID; import static com.google.common.truth.Truth.assertThat; @@ -53,7 +52,9 @@ import android.hardware.common.fmq.MQDescriptor; import android.hardware.power.ChannelConfig; import android.hardware.power.ChannelMessage; import android.hardware.power.CpuHeadroomParams; +import android.hardware.power.CpuHeadroomResult; import android.hardware.power.GpuHeadroomParams; +import android.hardware.power.GpuHeadroomResult; import android.hardware.power.IPower; import android.hardware.power.SessionConfig; import android.hardware.power.SessionTag; @@ -1251,67 +1252,98 @@ public class HintManagerServiceTest { CpuHeadroomParams halParams1 = new CpuHeadroomParams(); halParams1.calculationType = CpuHeadroomParams.CalculationType.MIN; halParams1.selectionType = CpuHeadroomParams.SelectionType.ALL; - halParams1.pid = Process.myPid(); + halParams1.tids = new int[]{Process.myPid()}; CpuHeadroomParamsInternal params2 = new CpuHeadroomParamsInternal(); params2.usesDeviceHeadroom = true; - params2.calculationType = CpuHeadroomParams.CalculationType.AVERAGE; + params2.calculationType = CpuHeadroomParams.CalculationType.MIN; params2.selectionType = CpuHeadroomParams.SelectionType.PER_CORE; CpuHeadroomParams halParams2 = new CpuHeadroomParams(); - halParams2.calculationType = CpuHeadroomParams.CalculationType.AVERAGE; + halParams2.calculationType = CpuHeadroomParams.CalculationType.MIN; halParams2.selectionType = CpuHeadroomParams.SelectionType.PER_CORE; - halParams2.pid = DEFAULT_HEADROOM_PID; + halParams2.tids = new int[]{}; + + CpuHeadroomParamsInternal params3 = new CpuHeadroomParamsInternal(); + params3.calculationType = CpuHeadroomParams.CalculationType.AVERAGE; + params3.selectionType = CpuHeadroomParams.SelectionType.ALL; + CpuHeadroomParams halParams3 = new CpuHeadroomParams(); + halParams3.calculationType = CpuHeadroomParams.CalculationType.AVERAGE; + halParams3.selectionType = CpuHeadroomParams.SelectionType.ALL; + halParams3.tids = new int[]{Process.myPid()}; + + // this params should not be cached as the window is not default + CpuHeadroomParamsInternal params4 = new CpuHeadroomParamsInternal(); + params4.calculationWindowMillis = 123; + CpuHeadroomParams halParams4 = new CpuHeadroomParams(); + halParams4.calculationType = CpuHeadroomParams.CalculationType.MIN; + halParams4.selectionType = CpuHeadroomParams.SelectionType.ALL; + halParams4.calculationWindowMillis = 123; + halParams4.tids = new int[]{Process.myPid()}; - float[] headroom1 = new float[] {0.1f}; - when(mIPowerMock.getCpuHeadroom(eq(halParams1))).thenReturn(headroom1); - float[] headroom2 = new float[] {0.1f, 0.5f}; - when(mIPowerMock.getCpuHeadroom(eq(halParams2))).thenReturn(headroom2); + float headroom1 = 0.1f; + CpuHeadroomResult halRet1 = CpuHeadroomResult.globalHeadroom(headroom1); + when(mIPowerMock.getCpuHeadroom(eq(halParams1))).thenReturn(halRet1); + float[] headroom2 = new float[] {0.2f, 0.2f}; + CpuHeadroomResult halRet2 = CpuHeadroomResult.perCoreHeadroom(headroom2); + when(mIPowerMock.getCpuHeadroom(eq(halParams2))).thenReturn(halRet2); + float headroom3 = 0.3f; + CpuHeadroomResult halRet3 = CpuHeadroomResult.globalHeadroom(headroom3); + when(mIPowerMock.getCpuHeadroom(eq(halParams3))).thenReturn(halRet3); + float headroom4 = 0.4f; + CpuHeadroomResult halRet4 = CpuHeadroomResult.globalHeadroom(headroom4); + when(mIPowerMock.getCpuHeadroom(eq(halParams4))).thenReturn(halRet4); HintManagerService service = createService(); clearInvocations(mIPowerMock); service.getBinderServiceInstance().getCpuHeadroomMinIntervalMillis(); verify(mIPowerMock, times(0)).getCpuHeadroomMinIntervalMillis(); - service.getBinderServiceInstance().getCpuHeadroom(params1); + assertEquals(halRet1, service.getBinderServiceInstance().getCpuHeadroom(params1)); verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams1)); - service.getBinderServiceInstance().getCpuHeadroom(params2); + assertEquals(halRet2, service.getBinderServiceInstance().getCpuHeadroom(params2)); verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams2)); + assertEquals(halRet3, service.getBinderServiceInstance().getCpuHeadroom(params3)); + verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams3)); + assertEquals(halRet4, service.getBinderServiceInstance().getCpuHeadroom(params4)); + verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams4)); // verify cache is working clearInvocations(mIPowerMock); - assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1), - 0.01f); - assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2), - 0.01f); - verify(mIPowerMock, times(0)).getCpuHeadroom(any()); + assertEquals(halRet1, service.getBinderServiceInstance().getCpuHeadroom(params1)); + assertEquals(halRet2, service.getBinderServiceInstance().getCpuHeadroom(params2)); + assertEquals(halRet3, service.getBinderServiceInstance().getCpuHeadroom(params3)); + assertEquals(halRet4, service.getBinderServiceInstance().getCpuHeadroom(params4)); + verify(mIPowerMock, times(1)).getCpuHeadroom(any()); + verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams1)); + verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams2)); + verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams3)); + verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams4)); // after 1 more second it should be served with cache still Thread.sleep(1000); clearInvocations(mIPowerMock); - assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1), - 0.01f); - assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2), - 0.01f); - verify(mIPowerMock, times(0)).getCpuHeadroom(any()); - - // after 1.5 more second it should be served with cache still as timer reset - Thread.sleep(1500); - clearInvocations(mIPowerMock); - assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1), - 0.01f); - assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2), - 0.01f); - verify(mIPowerMock, times(0)).getCpuHeadroom(any()); + assertEquals(halRet1, service.getBinderServiceInstance().getCpuHeadroom(params1)); + assertEquals(halRet2, service.getBinderServiceInstance().getCpuHeadroom(params2)); + assertEquals(halRet3, service.getBinderServiceInstance().getCpuHeadroom(params3)); + assertEquals(halRet4, service.getBinderServiceInstance().getCpuHeadroom(params4)); + verify(mIPowerMock, times(1)).getCpuHeadroom(any()); + verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams1)); + verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams2)); + verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams3)); + verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams4)); // after 2+ seconds it should be served from HAL as it exceeds 2000 millis interval - Thread.sleep(2100); + Thread.sleep(1100); clearInvocations(mIPowerMock); - assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1), - 0.01f); - assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2), - 0.01f); + assertEquals(halRet1, service.getBinderServiceInstance().getCpuHeadroom(params1)); + assertEquals(halRet2, service.getBinderServiceInstance().getCpuHeadroom(params2)); + assertEquals(halRet3, service.getBinderServiceInstance().getCpuHeadroom(params3)); + assertEquals(halRet4, service.getBinderServiceInstance().getCpuHeadroom(params4)); + verify(mIPowerMock, times(4)).getCpuHeadroom(any()); verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams1)); verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams2)); + verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams3)); + verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams4)); } @Test @@ -1322,59 +1354,52 @@ public class HintManagerServiceTest { halParams1.calculationType = GpuHeadroomParams.CalculationType.MIN; GpuHeadroomParamsInternal params2 = new GpuHeadroomParamsInternal(); + params2.calculationType = GpuHeadroomParams.CalculationType.AVERAGE; + params2.calculationWindowMillis = 123; GpuHeadroomParams halParams2 = new GpuHeadroomParams(); - params2.calculationType = - halParams2.calculationType = GpuHeadroomParams.CalculationType.AVERAGE; + halParams2.calculationType = GpuHeadroomParams.CalculationType.AVERAGE; + halParams2.calculationWindowMillis = 123; float headroom1 = 0.1f; - when(mIPowerMock.getGpuHeadroom(eq(halParams1))).thenReturn(headroom1); + GpuHeadroomResult halRet1 = GpuHeadroomResult.globalHeadroom(headroom1); + when(mIPowerMock.getGpuHeadroom(eq(halParams1))).thenReturn(halRet1); float headroom2 = 0.2f; - when(mIPowerMock.getGpuHeadroom(eq(halParams2))).thenReturn(headroom2); + GpuHeadroomResult halRet2 = GpuHeadroomResult.globalHeadroom(headroom2); + when(mIPowerMock.getGpuHeadroom(eq(halParams2))).thenReturn(halRet2); HintManagerService service = createService(); clearInvocations(mIPowerMock); service.getBinderServiceInstance().getGpuHeadroomMinIntervalMillis(); verify(mIPowerMock, times(0)).getGpuHeadroomMinIntervalMillis(); - assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1), - 0.01f); - assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2), - 0.01f); + assertEquals(halRet1, service.getBinderServiceInstance().getGpuHeadroom(params1)); + assertEquals(halRet2, service.getBinderServiceInstance().getGpuHeadroom(params2)); + verify(mIPowerMock, times(2)).getGpuHeadroom(any()); verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1)); verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2)); // verify cache is working clearInvocations(mIPowerMock); - assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1), - 0.01f); - assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2), - 0.01f); - verify(mIPowerMock, times(0)).getGpuHeadroom(any()); + assertEquals(halRet1, service.getBinderServiceInstance().getGpuHeadroom(params1)); + assertEquals(halRet2, service.getBinderServiceInstance().getGpuHeadroom(params2)); + verify(mIPowerMock, times(1)).getGpuHeadroom(any()); + verify(mIPowerMock, times(0)).getGpuHeadroom(eq(halParams1)); + verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2)); // after 1 more second it should be served with cache still Thread.sleep(1000); clearInvocations(mIPowerMock); - assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1), - 0.01f); - assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2), - 0.01f); - verify(mIPowerMock, times(0)).getGpuHeadroom(any()); - - // after 1.5 more second it should be served with cache still as timer reset - Thread.sleep(1500); - clearInvocations(mIPowerMock); - assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1), - 0.01f); - assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2), - 0.01f); - verify(mIPowerMock, times(0)).getGpuHeadroom(any()); + assertEquals(halRet1, service.getBinderServiceInstance().getGpuHeadroom(params1)); + assertEquals(halRet2, service.getBinderServiceInstance().getGpuHeadroom(params2)); + verify(mIPowerMock, times(1)).getGpuHeadroom(any()); + verify(mIPowerMock, times(0)).getGpuHeadroom(eq(halParams1)); + verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2)); // after 2+ seconds it should be served from HAL as it exceeds 2000 millis interval - Thread.sleep(2100); + Thread.sleep(1100); clearInvocations(mIPowerMock); - assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1), - 0.01f); - assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2), - 0.01f); + assertEquals(halRet1, service.getBinderServiceInstance().getGpuHeadroom(params1)); + assertEquals(halRet2, service.getBinderServiceInstance().getGpuHeadroom(params2)); + verify(mIPowerMock, times(2)).getGpuHeadroom(any()); verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1)); verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2)); } |