Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0211daf7 authored by Xiang Wang's avatar Xiang Wang
Browse files

Add support for thermal threshold callback

Bug: 360486877
Flag: android.os.allow_thermal_thresholds_callback
Test: atest ThermalManagerServiceTest ThermalManagerServiceMockingTest
Change-Id: Ic8e0a53b2a306ae74e75b9c3a5dafda723840448
parent ac973181
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -109,7 +109,7 @@ filegroup {
        ":android.hardware.radio.voice-V3-java-source",
        ":android.hardware.security.keymint-V3-java-source",
        ":android.hardware.security.secureclock-V1-java-source",
        ":android.hardware.thermal-V2-java-source",
        ":android.hardware.thermal-V3-java-source",
        ":android.hardware.tv.tuner-V3-java-source",
        ":android.security.apc-java-source",
        ":android.security.authorization-java-source",
+8 −0
Original line number Diff line number Diff line
@@ -90,6 +90,14 @@ flag {
    bug: "288119641"
}

flag {
    name: "allow_thermal_thresholds_callback"
    is_exported: true
    namespace: "game"
    description: "Enable thermal threshold callback"
    bug: "360486877"
}

flag {
    name: "android_os_build_vanilla_ice_cream"
    is_exported: true
+107 −75
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.content.Context;
import android.hardware.thermal.IThermal;
import android.hardware.thermal.IThermalChangedCallback;
import android.hardware.thermal.TemperatureThreshold;
import android.hardware.thermal.TemperatureType;
import android.hardware.thermal.ThrottlingSeverity;
import android.hardware.thermal.V1_0.ThermalStatus;
import android.hardware.thermal.V1_0.ThermalStatusCode;
@@ -134,6 +135,31 @@ public class ThermalManagerService extends SystemService {
    @VisibleForTesting
    final TemperatureWatcher mTemperatureWatcher = new TemperatureWatcher();

    private final ThermalHalWrapper.WrapperThermalChangedCallback mWrapperCallback =
            new ThermalHalWrapper.WrapperThermalChangedCallback() {
                @Override
                public void onTemperatureChanged(Temperature temperature) {
                    final long token = Binder.clearCallingIdentity();
                    try {
                        ThermalManagerService.this.onTemperatureChanged(temperature, true);
                    } finally {
                        Binder.restoreCallingIdentity(token);
                    }
                }

                @Override
                public void onThresholdChanged(TemperatureThreshold threshold) {
                    final long token = Binder.clearCallingIdentity();
                    try {
                        synchronized (mTemperatureWatcher.mSamples) {
                            mTemperatureWatcher.updateTemperatureThresholdLocked(threshold, true);
                        }
                    } finally {
                        Binder.restoreCallingIdentity(token);
                    }
                }
            };

    private final Context mContext;

    public ThermalManagerService(Context context) {
@@ -146,7 +172,7 @@ public class ThermalManagerService extends SystemService {
        mContext = context;
        mHalWrapper = halWrapper;
        if (halWrapper != null) {
            halWrapper.setCallback(this::onTemperatureChangedCallback);
            halWrapper.setCallback(mWrapperCallback);
        }
        mStatus = Temperature.THROTTLING_NONE;
    }
@@ -171,19 +197,19 @@ public class ThermalManagerService extends SystemService {
            // Connect to HAL and post to listeners.
            boolean halConnected = (mHalWrapper != null);
            if (!halConnected) {
                mHalWrapper = new ThermalHalAidlWrapper(this::onTemperatureChangedCallback);
                mHalWrapper = new ThermalHalAidlWrapper(mWrapperCallback);
                halConnected = mHalWrapper.connectToHal();
            }
            if (!halConnected) {
                mHalWrapper = new ThermalHal20Wrapper(this::onTemperatureChangedCallback);
                mHalWrapper = new ThermalHal20Wrapper(mWrapperCallback);
                halConnected = mHalWrapper.connectToHal();
            }
            if (!halConnected) {
                mHalWrapper = new ThermalHal11Wrapper(this::onTemperatureChangedCallback);
                mHalWrapper = new ThermalHal11Wrapper(mWrapperCallback);
                halConnected = mHalWrapper.connectToHal();
            }
            if (!halConnected) {
                mHalWrapper = new ThermalHal10Wrapper(this::onTemperatureChangedCallback);
                mHalWrapper = new ThermalHal10Wrapper(mWrapperCallback);
                halConnected = mHalWrapper.connectToHal();
            }
            if (!halConnected) {
@@ -200,7 +226,7 @@ public class ThermalManagerService extends SystemService {
                onTemperatureChanged(temperatures.get(i), false);
            }
            onTemperatureMapChangedLocked();
            mTemperatureWatcher.updateThresholds();
            mTemperatureWatcher.getAndUpdateThresholds();
            mHalReady.set(true);
        }
    }
@@ -335,16 +361,6 @@ public class ThermalManagerService extends SystemService {
        }
    }

    /* HwBinder callback **/
    private void onTemperatureChangedCallback(Temperature temperature) {
        final long token = Binder.clearCallingIdentity();
        try {
            onTemperatureChanged(temperature, true);
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    private void registerStatsCallbacks() {
        final StatsManager statsManager = mContext.getSystemService(StatsManager.class);
        if (statsManager != null) {
@@ -924,19 +940,19 @@ public class ThermalManagerService extends SystemService {
        /** Lock to protect HAL handle. */
        protected final Object mHalLock = new Object();

        @FunctionalInterface
        interface TemperatureChangedCallback {
            void onValues(Temperature temperature);
        interface WrapperThermalChangedCallback {
            void onTemperatureChanged(Temperature temperature);
            void onThresholdChanged(TemperatureThreshold threshold);
        }

        /** Temperature callback. */
        protected TemperatureChangedCallback mCallback;
        protected WrapperThermalChangedCallback mCallback;

        /** Cookie for matching the right end point. */
        protected static final int THERMAL_HAL_DEATH_COOKIE = 5612;

        @VisibleForTesting
        protected void setCallback(TemperatureChangedCallback cb) {
        protected void setCallback(WrapperThermalChangedCallback cb) {
            mCallback = cb;
        }

@@ -959,7 +975,7 @@ public class ThermalManagerService extends SystemService {
                List<Temperature> temperatures = getCurrentTemperatures(false, 0);
                final int count = temperatures.size();
                for (int i = 0; i < count; i++) {
                    mCallback.onValues(temperatures.get(i));
                    mCallback.onTemperatureChanged(temperatures.get(i));
                }
            }
        }
@@ -985,31 +1001,42 @@ public class ThermalManagerService extends SystemService {
        private IThermal mInstance = null;

        /** Callback for Thermal HAL AIDL. */
        private final IThermalChangedCallback mThermalChangedCallback =
        private final IThermalChangedCallback mThermalCallbackAidl =
                new IThermalChangedCallback.Stub() {
                    @Override public void notifyThrottling(
                            android.hardware.thermal.Temperature temperature)
                            throws RemoteException {
                    @Override
                    public void notifyThrottling(
                            android.hardware.thermal.Temperature temperature) {
                        Temperature svcTemperature = new Temperature(temperature.value,
                                temperature.type, temperature.name, temperature.throttlingStatus);
                        final long token = Binder.clearCallingIdentity();
                        try {
                            mCallback.onValues(svcTemperature);
                            mCallback.onTemperatureChanged(svcTemperature);
                        } finally {
                            Binder.restoreCallingIdentity(token);
                        }
                    }

            @Override public int getInterfaceVersion() throws RemoteException {
                    @Override
                    public void notifyThresholdChanged(TemperatureThreshold threshold) {
                        if (Flags.allowThermalThresholdsCallback()) {
                            if (threshold.type == TemperatureType.SKIN) {
                                mCallback.onThresholdChanged(threshold);
                            }
                        }
                    }

                    @Override
                    public int getInterfaceVersion() throws RemoteException {
                        return this.VERSION;
                    }

            @Override public String getInterfaceHash() throws RemoteException {
                    @Override
                    public String getInterfaceHash() throws RemoteException {
                        return this.HASH;
                    }
                };

        ThermalHalAidlWrapper(TemperatureChangedCallback callback) {
        ThermalHalAidlWrapper(WrapperThermalChangedCallback callback) {
            mCallback = callback;
        }

@@ -1153,7 +1180,7 @@ public class ThermalManagerService extends SystemService {
        @VisibleForTesting
        void registerThermalChangedCallback() {
            try {
                mInstance.registerThermalChangedCallback(mThermalChangedCallback);
                mInstance.registerThermalChangedCallback(mThermalCallbackAidl);
            } catch (IllegalArgumentException | IllegalStateException e) {
                Slog.e(TAG, "Couldn't registerThermalChangedCallback due to invalid status",
                        e);
@@ -1185,7 +1212,7 @@ public class ThermalManagerService extends SystemService {
        @GuardedBy("mHalLock")
        private android.hardware.thermal.V1_0.IThermal mThermalHal10 = null;

        ThermalHal10Wrapper(TemperatureChangedCallback callback) {
        ThermalHal10Wrapper(WrapperThermalChangedCallback callback) {
            mCallback = callback;
        }

@@ -1317,14 +1344,14 @@ public class ThermalManagerService extends SystemService {
                                        : Temperature.THROTTLING_NONE);
                        final long token = Binder.clearCallingIdentity();
                        try {
                            mCallback.onValues(thermalSvcTemp);
                            mCallback.onTemperatureChanged(thermalSvcTemp);
                        } finally {
                            Binder.restoreCallingIdentity(token);
                        }
                    }
                };

        ThermalHal11Wrapper(TemperatureChangedCallback callback) {
        ThermalHal11Wrapper(WrapperThermalChangedCallback callback) {
            mCallback = callback;
        }

@@ -1455,14 +1482,14 @@ public class ThermalManagerService extends SystemService {
                                temperature.throttlingStatus);
                        final long token = Binder.clearCallingIdentity();
                        try {
                            mCallback.onValues(thermalSvcTemp);
                            mCallback.onTemperatureChanged(thermalSvcTemp);
                        } finally {
                            Binder.restoreCallingIdentity(token);
                        }
                    }
                };

        ThermalHal20Wrapper(TemperatureChangedCallback callback) {
        ThermalHal20Wrapper(WrapperThermalChangedCallback callback) {
            mCallback = callback;
        }

@@ -1627,47 +1654,51 @@ public class ThermalManagerService extends SystemService {
        @VisibleForTesting
        long mInactivityThresholdMillis = INACTIVITY_THRESHOLD_MILLIS;

        void updateThresholds() {
        void getAndUpdateThresholds() {
            List<TemperatureThreshold> thresholds =
                        mHalWrapper.getTemperatureThresholds(true, Temperature.TYPE_SKIN);
            synchronized (mSamples) {
                if (Flags.allowThermalHeadroomThresholds()) {
                    Arrays.fill(mHeadroomThresholds, Float.NaN);
                }
                for (int t = 0; t < thresholds.size(); ++t) {
                    TemperatureThreshold threshold = thresholds.get(t);
                for (final TemperatureThreshold threshold : thresholds) {
                    updateTemperatureThresholdLocked(threshold, false);
                }
            }
        }

        // For an older device with multiple SKIN sensors, we will set a severity's headroom
        // threshold based on the minimum value of all as a workaround, unless override.
        @GuardedBy("mSamples")
        void updateTemperatureThresholdLocked(TemperatureThreshold threshold, boolean override) {
            if (threshold.hotThrottlingThresholds.length <= ThrottlingSeverity.SEVERE) {
                        continue;
                return;
            }
            float severeThreshold =
                    threshold.hotThrottlingThresholds[ThrottlingSeverity.SEVERE];
                    if (!Float.isNaN(severeThreshold)) {
            if (Float.isNaN(severeThreshold)) {
                return;
            }
            mSevereThresholds.put(threshold.name, severeThreshold);
                        if (Flags.allowThermalHeadroomThresholds()) {
            if (!Flags.allowThermalHeadroomThresholds()) {
                return;
            }
            if (override) {
                Arrays.fill(mHeadroomThresholds, Float.NaN);
            }
            for (int severity = ThrottlingSeverity.LIGHT;
                    severity <= ThrottlingSeverity.SHUTDOWN; severity++) {
                if (threshold.hotThrottlingThresholds.length > severity) {
                                    updateHeadroomThreshold(severity,
                                            threshold.hotThrottlingThresholds[severity],
                                            severeThreshold);
                                }
                            }
                        }
                    }
                }
            }
                    float t = threshold.hotThrottlingThresholds[severity];
                    if (Float.isNaN(t)) {
                        continue;
                    }

        // For an older device with multiple SKIN sensors, we will set a severity's headroom
        // threshold based on the minimum value of all as a workaround.
        void updateHeadroomThreshold(int severity, float threshold, float severeThreshold) {
            if (!Float.isNaN(threshold)) {
                    synchronized (mSamples) {
                        if (severity == ThrottlingSeverity.SEVERE) {
                            mHeadroomThresholds[severity] = 1.0f;
                        return;
                            continue;
                        }
                    float headroom = normalizeTemperature(threshold, severeThreshold);
                        float headroom = normalizeTemperature(t, severeThreshold);
                        if (Float.isNaN(mHeadroomThresholds[severity])) {
                            mHeadroomThresholds[severity] = headroom;
                        } else {
@@ -1677,6 +1708,7 @@ public class ThermalManagerService extends SystemService {
                    }
                }
            }
        }

        private static final int RING_BUFFER_SIZE = 30;

+1 −1
Original line number Diff line number Diff line
@@ -191,7 +191,7 @@ cc_defaults {
        "android.hardware.power.stats@1.0",
        "android.hardware.power.stats-V1-ndk",
        "android.hardware.thermal@1.0",
        "android.hardware.thermal-V2-ndk",
        "android.hardware.thermal-V3-ndk",
        "android.hardware.tv.input@1.0",
        "android.hardware.tv.input-V2-ndk",
        "android.hardware.vibrator-V3-ndk",
+76 −13
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.power;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

@@ -29,10 +30,16 @@ import android.hardware.thermal.TemperatureType;
import android.hardware.thermal.ThrottlingSeverity;
import android.os.Binder;
import android.os.CoolingDevice;
import android.os.Flags;
import android.os.RemoteException;
import android.os.Temperature;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;

import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
@@ -40,16 +47,36 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;


public class ThermalManagerServiceMockingTest {
    @Mock private IThermal mAidlHalMock;
    @ClassRule
    public static final SetFlagsRule.ClassRule mSetFlagsClassRule = new SetFlagsRule.ClassRule();
    @Rule
    public final SetFlagsRule mSetFlagsRule = mSetFlagsClassRule.createSetFlagsRule();

    @Mock
    private IThermal mAidlHalMock;
    private Binder mAidlBinder = new Binder();
    private CompletableFuture<Temperature> mTemperatureFuture;
    private ThermalManagerService.ThermalHalWrapper.TemperatureChangedCallback mTemperatureCallback;
    private CompletableFuture<TemperatureThreshold> mThresholdFuture;
    private ThermalManagerService.ThermalHalWrapper.WrapperThermalChangedCallback
            mTemperatureCallback =
            new ThermalManagerService.ThermalHalWrapper.WrapperThermalChangedCallback() {
                @Override
                public void onTemperatureChanged(Temperature temperature) {
                    mTemperatureFuture.complete(temperature);
                }

                @Override
                public void onThresholdChanged(TemperatureThreshold threshold) {
                    mThresholdFuture.complete(threshold);
                }
            };
    private ThermalManagerService.ThermalHalAidlWrapper mAidlWrapper;
    @Captor
    ArgumentCaptor<IThermalChangedCallback> mAidlCallbackCaptor;
@@ -60,27 +87,63 @@ public class ThermalManagerServiceMockingTest {
        Mockito.when(mAidlHalMock.asBinder()).thenReturn(mAidlBinder);
        mAidlBinder.attachInterface(mAidlHalMock, IThermal.class.getName());
        mTemperatureFuture = new CompletableFuture<>();
        mTemperatureCallback = temperature -> mTemperatureFuture.complete(temperature);
        mThresholdFuture = new CompletableFuture<>();
        mAidlWrapper = new ThermalManagerService.ThermalHalAidlWrapper(mTemperatureCallback);
        mAidlWrapper.initProxyAndRegisterCallback(mAidlBinder);
    }

    @Test
    @EnableFlags({Flags.FLAG_ALLOW_THERMAL_THRESHOLDS_CALLBACK})
    public void setCallback_aidl() throws Exception {
        Mockito.verify(mAidlHalMock, Mockito.times(1)).registerThermalChangedCallback(
                mAidlCallbackCaptor.capture());
        android.hardware.thermal.Temperature halT =
        android.hardware.thermal.Temperature halTemperature =
                new android.hardware.thermal.Temperature();
        halT.type = TemperatureType.SOC;
        halT.name = "test";
        halT.throttlingStatus = ThrottlingSeverity.SHUTDOWN;
        halT.value = 99.0f;
        mAidlCallbackCaptor.getValue().notifyThrottling(halT);
        halTemperature.type = TemperatureType.SOC;
        halTemperature.name = "test";
        halTemperature.throttlingStatus = ThrottlingSeverity.SHUTDOWN;
        halTemperature.value = 99.0f;

        android.hardware.thermal.TemperatureThreshold halThreshold =
                new android.hardware.thermal.TemperatureThreshold();
        halThreshold.type = TemperatureType.SKIN;
        halThreshold.name = "test";
        halThreshold.hotThrottlingThresholds = new float[ThrottlingSeverity.SHUTDOWN + 1];
        Arrays.fill(halThreshold.hotThrottlingThresholds, Float.NaN);
        halThreshold.hotThrottlingThresholds[ThrottlingSeverity.SEVERE] = 44.0f;

        mAidlCallbackCaptor.getValue().notifyThrottling(halTemperature);
        mAidlCallbackCaptor.getValue().notifyThresholdChanged(halThreshold);

        Temperature temperature = mTemperatureFuture.get(100, TimeUnit.MILLISECONDS);
        assertEquals(halT.name, temperature.getName());
        assertEquals(halT.type, temperature.getType());
        assertEquals(halT.value, temperature.getValue(), 0.1f);
        assertEquals(halT.throttlingStatus, temperature.getStatus());
        assertEquals(halTemperature.name, temperature.getName());
        assertEquals(halTemperature.type, temperature.getType());
        assertEquals(halTemperature.value, temperature.getValue(), 0.1f);
        assertEquals(halTemperature.throttlingStatus, temperature.getStatus());

        TemperatureThreshold threshold = mThresholdFuture.get(100, TimeUnit.MILLISECONDS);
        assertEquals(halThreshold.name, threshold.name);
        assertEquals(halThreshold.type, threshold.type);
        assertArrayEquals(halThreshold.hotThrottlingThresholds, threshold.hotThrottlingThresholds,
                0.01f);
    }

    @Test
    @DisableFlags({Flags.FLAG_ALLOW_THERMAL_THRESHOLDS_CALLBACK})
    public void setCallback_aidl_allow_thermal_thresholds_callback_false() throws Exception {
        Mockito.verify(mAidlHalMock, Mockito.times(1)).registerThermalChangedCallback(
                mAidlCallbackCaptor.capture());
        android.hardware.thermal.TemperatureThreshold halThreshold =
                new android.hardware.thermal.TemperatureThreshold();
        halThreshold.type = TemperatureType.SOC;
        halThreshold.name = "test";
        halThreshold.hotThrottlingThresholds = new float[ThrottlingSeverity.SHUTDOWN + 1];
        Arrays.fill(halThreshold.hotThrottlingThresholds, Float.NaN);
        halThreshold.hotThrottlingThresholds[ThrottlingSeverity.SEVERE] = 44.0f;

        mAidlCallbackCaptor.getValue().notifyThresholdChanged(halThreshold);
        Thread.sleep(1000);
        assertFalse(mThresholdFuture.isDone());
    }

    @Test
Loading