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

Commit 393c8e64 authored by Xiang Wang's avatar Xiang Wang Committed by Android (Google) Code Review
Browse files

Merge "Add support for thermal threshold callback" into main

parents 5c0fed85 0211daf7
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