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

Commit 2fc0463b authored by Dmitri Plotnikov's avatar Dmitri Plotnikov
Browse files

Do not crash system server on powerstats HAL errors

Bug: 338340054
Test: added an explicit exception and confirmed the fix
Flag: EXEMPT_bugfix
Change-Id: I7a4617a55fec9d2d7742ebe1746b1a717fddfcf6
parent f28c6040
Loading
Loading
Loading
Loading
+29 −5
Original line number Diff line number Diff line
@@ -304,12 +304,22 @@ public class PowerStatsService extends SystemService {
    @Override
    public void onStart() {
        if (getPowerStatsHal().isInitialized()) {
            mPowerStatsInternal = new LocalService();
            publishLocalService(PowerStatsInternal.class, mPowerStatsInternal);
            publishLocalService(PowerStatsInternal.class, getPowerStatsInternal());
        }
        publishBinderService(Context.POWER_STATS_SERVICE, mService);
    }

    /**
     * Returns the PowerStatsInternal associated with this service, maybe creating it if needed.
     */
    @VisibleForTesting
    public PowerStatsInternal getPowerStatsInternal() {
        if (mPowerStatsInternal == null) {
            mPowerStatsInternal = new LocalService();
        }
        return mPowerStatsInternal;
    }

    private void onSystemServicesReady() {
        mPullAtomCallback = mInjector.createStatsPullerImpl(mContext, mPowerStatsInternal);
        mDeviceConfigListener.startListening();
@@ -456,7 +466,13 @@ public class PowerStatsService extends SystemService {

    private void getEnergyConsumedAsync(CompletableFuture<EnergyConsumerResult[]> future,
            int[] energyConsumerIds) {
        EnergyConsumerResult[] results = getPowerStatsHal().getEnergyConsumed(energyConsumerIds);
        EnergyConsumerResult[] results;
        try {
            results = getPowerStatsHal().getEnergyConsumed(energyConsumerIds);
        } catch (Exception e) {
            future.completeExceptionally(e);
            return;
        }

        // STOPSHIP(253292374): Remove once missing EnergyConsumer results issue is resolved.
        EnergyConsumer[] energyConsumers = getEnergyConsumerInfo();
@@ -523,12 +539,20 @@ public class PowerStatsService extends SystemService {

    private void getStateResidencyAsync(CompletableFuture<StateResidencyResult[]> future,
            int[] powerEntityIds) {
        try {
            future.complete(getPowerStatsHal().getStateResidency(powerEntityIds));
        } catch (Exception e) {
            future.completeExceptionally(e);
        }
    }

    private void readEnergyMeterAsync(CompletableFuture<EnergyMeasurement[]> future,
            int[] channelIds) {
        try {
            future.complete(getPowerStatsHal().readEnergyMeter(channelIds));
        } catch (Exception e) {
            future.completeExceptionally(e);
        }
    }

    private static class PowerMonitorState {
+39 −0
Original line number Diff line number Diff line
@@ -74,6 +74,8 @@ import java.nio.file.Files;
import java.util.Arrays;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
@@ -221,6 +223,7 @@ public class PowerStatsServiceTest {
    };

    public static final class TestPowerStatsHALWrapper implements IPowerStatsHALWrapper {
        public RuntimeException exception;
        public EnergyConsumerResult[] energyConsumerResults;
        public EnergyMeasurement[] energyMeasurements;

@@ -243,6 +246,9 @@ public class PowerStatsServiceTest {

        @Override
        public StateResidencyResult[] getStateResidency(int[] powerEntityIds) {
            if (exception != null) {
                throw exception;
            }
            StateResidencyResult[] stateResidencyResultList =
                    new StateResidencyResult[POWER_ENTITY_COUNT];
            for (int i = 0; i < stateResidencyResultList.length; i++) {
@@ -294,6 +300,9 @@ public class PowerStatsServiceTest {

        @Override
        public EnergyConsumerResult[] getEnergyConsumed(int[] energyConsumerIds) {
            if (exception != null) {
                throw exception;
            }
            return energyConsumerResults;
        }

@@ -322,6 +331,9 @@ public class PowerStatsServiceTest {

        @Override
        public EnergyMeasurement[] readEnergyMeter(int[] channelIds) {
            if (exception != null) {
                throw exception;
            }
            return energyMeasurements;
        }

@@ -1222,4 +1234,31 @@ public class PowerStatsServiceTest {
        assertThrows(NullPointerException.class, () -> iPowerStatsService.getPowerMonitorReadings(
                new int[] {0}, null));
    }

    @Test
    public void getEnergyConsumedAsync_halException() {
        mPowerStatsHALWrapper.exception = new IllegalArgumentException();
        CompletableFuture<EnergyConsumerResult[]> future =
                mService.getPowerStatsInternal().getEnergyConsumedAsync(new int[]{1});
        ExecutionException exception = assertThrows(ExecutionException.class, future::get);
        assertThat(exception.getCause()).isInstanceOf(IllegalArgumentException.class);
    }

    @Test
    public void getStateResidencyAsync_halException() {
        mPowerStatsHALWrapper.exception = new IllegalArgumentException();
        CompletableFuture<StateResidencyResult[]> future =
                mService.getPowerStatsInternal().getStateResidencyAsync(new int[]{1});
        ExecutionException exception = assertThrows(ExecutionException.class, future::get);
        assertThat(exception.getCause()).isInstanceOf(IllegalArgumentException.class);
    }

    @Test
    public void readEnergyMeterAsync_halException() {
        mPowerStatsHALWrapper.exception = new IllegalArgumentException();
        CompletableFuture<EnergyMeasurement[]> future =
                mService.getPowerStatsInternal().readEnergyMeterAsync(new int[]{1});
        ExecutionException exception = assertThrows(ExecutionException.class, future::get);
        assertThat(exception.getCause()).isInstanceOf(IllegalArgumentException.class);
    }
}