blob: bf461f49c35fb9a4d6a0934364b0b1c1ea332732 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.clockwork.displayoffload;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Bundle;
import android.os.IHwBinder;
import android.os.RemoteException;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import vendor.google_clockwork.displayoffload.V1_0.Status;
/**
* Tests for {@link com.google.android.clockwork.displayoffload.HalAdapter}.
*/
@RunWith(AndroidJUnit4.class)
public class HalAdapterTest {
private final Context mContext = ApplicationProvider.getApplicationContext();
private final HalAdapter mHalAdapter = spy(new HalAdapter(mContext));
private final FakeHalImplV1_1 mFakeHalImplV1_1 = spy(new FakeHalImplV1_1());
private final FakeHalImplV2_0 mFakeHalImplV2_0 = spy(new FakeHalImplV2_0());
private final IHwBinder fakeBinder1 = spy(new FakeHwBinder());
private final IHwBinder fakeBinder2 = spy(new FakeHwBinder());
private final HalAdapter.HalListener mFakeHalListener =
spy(
new HalAdapter.HalListener() {
@Override
public void onHalRegistered() {}
@Override
public void onHalDied() {}
});
@Before
public void setup() {
mFakeHalImplV1_1.mHwBinder = fakeBinder1;
mFakeHalImplV2_0.mHwBinder = fakeBinder2;
}
@Test
public void testHalConnectionReporting() {
// No HAL connected
assertThat(mHalAdapter.isHalConnected()).isFalse();
assertThat(mHalAdapter.getConnectedHalVersions()).hasSize(0);
// V1
mHalAdapter.mDisplayOffloadV1_0 = mFakeHalImplV1_1;
mHalAdapter.mDisplayOffloadV1_1 = null;
mHalAdapter.mDisplayOffloadV2_0 = null;
assertThat(mHalAdapter.isHalConnected()).isTrue();
assertThat(mHalAdapter.getConnectedHalVersions()).hasSize(1);
// V1_1
mHalAdapter.mDisplayOffloadV1_0 = mFakeHalImplV1_1;
mHalAdapter.mDisplayOffloadV1_1 = mFakeHalImplV1_1;
mHalAdapter.mDisplayOffloadV2_0 = null;
assertThat(mHalAdapter.isHalConnected()).isTrue();
assertThat(mHalAdapter.getConnectedHalVersions()).hasSize(2);
// V2_0
mHalAdapter.mDisplayOffloadV1_0 = null;
mHalAdapter.mDisplayOffloadV1_1 = null;
mHalAdapter.mDisplayOffloadV2_0 = mFakeHalImplV2_0;
assertThat(mHalAdapter.isHalConnected()).isTrue();
assertThat(mHalAdapter.getConnectedHalVersions()).hasSize(1);
// V1_1 & V2_0
mHalAdapter.mDisplayOffloadV1_0 = mFakeHalImplV1_1;
mHalAdapter.mDisplayOffloadV1_1 = mFakeHalImplV1_1;
mHalAdapter.mDisplayOffloadV2_0 = mFakeHalImplV2_0;
assertThat(mHalAdapter.isHalConnected()).isTrue();
assertThat(mHalAdapter.getConnectedHalVersions()).hasSize(3);
}
@Test
public void testSetBrightnessConfiguration() throws RemoteException {
boolean brightenOnWristTilt = true;
int status;
ArrayList<Short> alsThresholds = new ArrayList<>(
Arrays.asList(new Short[]{0x1, 0x2, 0x3}));
ArrayList<Short> brightnessValuesDim = new ArrayList<>(
Arrays.asList(new Short[]{0x4, 0x5, 0x6}));
ArrayList<Short> brightnessValuesBright = new ArrayList<>(
Arrays.asList(new Short[]{0x7, 0x8, 0x9}));
// No HAL connected, don't crash
status = mHalAdapter.setBrightnessConfiguration(brightenOnWristTilt, alsThresholds,
brightnessValuesDim, brightnessValuesBright);
assertThat(status).isNotEqualTo(Status.OK);
verifyNoMoreInteractions(mFakeHalImplV1_1);
verifyNoMoreInteractions(mFakeHalImplV2_0);
// V1
mHalAdapter.mDisplayOffloadV1_0 = mFakeHalImplV1_1;
when(mFakeHalImplV1_1.setBrightnessConfiguration(anyBoolean(),any(),any(),any()))
.thenReturn(Status.OK);
status = mHalAdapter.setBrightnessConfiguration(brightenOnWristTilt, alsThresholds,
brightnessValuesDim, brightnessValuesBright);
assertThat(status).isEqualTo(Status.OK);
verify(mFakeHalImplV1_1).setBrightnessConfiguration(eq(brightenOnWristTilt),
eq(alsThresholds), eq(brightnessValuesDim), eq(brightnessValuesBright));
verifyNoMoreInteractions(mFakeHalImplV2_0);
// V2
mHalAdapter.mDisplayOffloadV2_0 = mFakeHalImplV2_0;
when(mFakeHalImplV2_0.setBrightnessConfiguration(anyBoolean(),any(),any(),any()))
.thenReturn(Status.OK);
status = mHalAdapter.setBrightnessConfiguration(brightenOnWristTilt, alsThresholds,
brightnessValuesDim, brightnessValuesBright);
assertThat(status).isEqualTo(Status.OK);
verify(mFakeHalImplV2_0).setBrightnessConfiguration(eq(brightenOnWristTilt),
eq(alsThresholds), eq(brightnessValuesDim), eq(brightnessValuesBright));
verifyNoMoreInteractions(mFakeHalImplV1_1);
}
@Test
public void testIsRenderControlSupported() {
// No HAL connected, don't crash
assertThat(mHalAdapter.isRenderControlSupported()).isFalse();
// V1 connected
mHalAdapter.mDisplayOffloadV1_0 = mFakeHalImplV1_1;
mHalAdapter.mDisplayOffloadV1_1 = mFakeHalImplV1_1;
assertThat(mHalAdapter.isRenderControlSupported()).isTrue();
// V2 connected
mHalAdapter.mDisplayOffloadV2_0 = mFakeHalImplV2_0;
assertThat(mHalAdapter.isRenderControlSupported()).isTrue();
}
@Test
public void testBeginEndDisplayControl() throws RemoteException {
// No HAL connected, don't crash
mHalAdapter.beginDisplay();
mHalAdapter.beginRendering();
mHalAdapter.endRendering();
mHalAdapter.endDisplay();
verifyNoMoreInteractions(mFakeHalImplV1_1);
verifyNoMoreInteractions(mFakeHalImplV2_0);
// V1 connected
mHalAdapter.mDisplayOffloadV1_0 = mFakeHalImplV1_1;
mHalAdapter.mDisplayOffloadV1_1 = mFakeHalImplV1_1;
mHalAdapter.beginDisplay();
mHalAdapter.beginRendering();
mHalAdapter.endRendering();
mHalAdapter.endDisplay();
// Only V1 should be called
verify(mFakeHalImplV1_1).beginDisplay();
verify(mFakeHalImplV1_1).beginRendering();
verify(mFakeHalImplV1_1).endRendering();
verify(mFakeHalImplV1_1).endDisplay();
verifyNoMoreInteractions(mFakeHalImplV2_0);
// V2 connected
mHalAdapter.mDisplayOffloadV1_0 = mFakeHalImplV1_1;
mHalAdapter.mDisplayOffloadV1_1 = mFakeHalImplV1_1;
mHalAdapter.mDisplayOffloadV2_0 = mFakeHalImplV2_0;
mHalAdapter.beginDisplay();
mHalAdapter.beginRendering();
mHalAdapter.endRendering();
mHalAdapter.endDisplay();
// Should prefer V2 when V1 is also connected
verify(mFakeHalImplV2_0).beginDisplayControl();
verify(mFakeHalImplV2_0).beginRendering();
verify(mFakeHalImplV2_0).endRendering();
verify(mFakeHalImplV2_0).endDisplayControl();
verifyNoMoreInteractions(mFakeHalImplV1_1);
}
@Test
public void testResetResource() throws RemoteException {
// No HAL connected, don't crash
mHalAdapter.resetResource();
verifyNoMoreInteractions(mFakeHalImplV1_1);
verifyNoMoreInteractions(mFakeHalImplV2_0);
// V1
mHalAdapter.mDisplayOffloadV1_0 = mFakeHalImplV1_1;
mHalAdapter.mDisplayOffloadV1_1 = mFakeHalImplV1_1;
mHalAdapter.resetResource();
verify(mFakeHalImplV1_1).resetResource();
verifyNoMoreInteractions(mFakeHalImplV2_0);
// V2
mHalAdapter.mDisplayOffloadV2_0 = mFakeHalImplV2_0;
mHalAdapter.resetResource();
verify(mFakeHalImplV2_0).reset();
verifyNoMoreInteractions(mFakeHalImplV1_1);
}
@Test
public void testSetRootResourceId() throws RemoteException {
final int rootId = 42;
// No HAL connected, don't crash
mHalAdapter.setRoot(rootId);
verifyNoMoreInteractions(mFakeHalImplV1_1);
verifyNoMoreInteractions(mFakeHalImplV2_0);
mHalAdapter.mDisplayOffloadV1_0 = mFakeHalImplV1_1;
mHalAdapter.mDisplayOffloadV1_1 = mFakeHalImplV1_1;
mHalAdapter.setRoot(rootId);
verify(mFakeHalImplV1_1).setRootResourceId(eq(rootId));
verifyNoMoreInteractions(mFakeHalImplV2_0);
mHalAdapter.mDisplayOffloadV2_0 = mFakeHalImplV2_0;
mHalAdapter.setRoot(rootId);
verify(mFakeHalImplV2_0).setRootResourceId(eq(rootId));
verifyNoMoreInteractions(mFakeHalImplV1_1);
}
@Test
public void testFetchDataSnapshot() throws RemoteException {
// No HAL connected, don't crash
Bundle bundle = mHalAdapter.fetchDataSnapshot();
assertThat(bundle).isNull();
verifyNoMoreInteractions(mFakeHalImplV1_1);
verifyNoMoreInteractions(mFakeHalImplV2_0);
// V1
mHalAdapter.mDisplayOffloadV1_0 = mFakeHalImplV1_1;
mHalAdapter.mDisplayOffloadV1_1 = mFakeHalImplV1_1;
bundle = mHalAdapter.fetchDataSnapshot();
assertThat(bundle).isNotNull();
verify(mFakeHalImplV1_1).fetchDataSnapshot();
verifyNoMoreInteractions(mFakeHalImplV2_0);
// V2
mHalAdapter.mDisplayOffloadV2_0 = mFakeHalImplV2_0;
bundle = mHalAdapter.fetchDataSnapshot();
assertThat(bundle).isNotNull();
verify(mFakeHalImplV2_0).fetchDataSnapshot();
verifyNoMoreInteractions(mFakeHalImplV1_1);
}
@Test
public void testSendNoHalAvailable() throws RemoteException, DisplayOffloadException {
// No HAL connected, don't crash
assertThat(mHalAdapter.send(new Object())).isEqualTo(Status.OK);
verifyNoMoreInteractions(mFakeHalImplV1_1);
verifyNoMoreInteractions(mFakeHalImplV2_0);
}
@Test
public void testSendV1HALTypesConnected() throws RemoteException, DisplayOffloadException {
mHalAdapter.mDisplayOffloadV1_0 = mFakeHalImplV1_1;
mHalAdapter.mDisplayOffloadV1_1 = mFakeHalImplV1_1;
mHalAdapter.mDisplayOffloadV2_0 = null;
verifySendHalObject(mFakeHalImplV1_1);
verifyNoMoreInteractions(mFakeHalImplV2_0);
}
@Test
public void testSendV2HALTypesConnected() throws RemoteException, DisplayOffloadException {
mHalAdapter.mDisplayOffloadV1_0 = null;
mHalAdapter.mDisplayOffloadV1_1 = null;
mHalAdapter.mDisplayOffloadV2_0 = mFakeHalImplV2_0;
verifySendHalObject(mFakeHalImplV2_0);
verifyNoMoreInteractions(mFakeHalImplV1_1);
}
@Test
public void testSetLocaleConfig() throws RemoteException {
// No HAL connected, don't crash
mHalAdapter.setLocaleConfig();
verifyNoMoreInteractions(mFakeHalImplV1_1);
verifyNoMoreInteractions(mFakeHalImplV2_0);
// V1
mHalAdapter.mDisplayOffloadV1_0 = mFakeHalImplV1_1;
mHalAdapter.mDisplayOffloadV1_1 = mFakeHalImplV1_1;
mHalAdapter.setLocaleConfig();
verify(mFakeHalImplV1_1).setLocaleConfig(eq(
LocaleHelper.getCurrentLocaleConfig(mContext).getHalObject()));
verifyNoMoreInteractions(mFakeHalImplV2_0);
// V2
mHalAdapter.mDisplayOffloadV2_0 = mFakeHalImplV2_0;
mHalAdapter.setLocaleConfig();
verify(mFakeHalImplV2_0).setLocaleConfig(eq(
LocaleHelper.getCurrentLocaleConfig(mContext).getHalObject()));
verifyNoMoreInteractions(mFakeHalImplV1_1);
}
@Test
public void testOnRegistration() throws RemoteException {
// V1
mHalAdapter.onRegistration(
vendor.google_clockwork.displayoffload.V1_0.IDisplayOffload.kInterfaceName,
"",
true);
verify(mHalAdapter, times(1)).registerHalV1(eq(null));
verifyNoMoreInteractions(mFakeHalImplV2_0);
// V2
mHalAdapter.onRegistration(
vendor.google_clockwork.displayoffload.V2_0.IDisplayOffload.kInterfaceName,
"",
true);
verify(mHalAdapter, times(1)).registerHalV2(eq(null));
verifyNoMoreInteractions(mFakeHalImplV1_1);
}
@Test
public void testRegisterHal() {
mHalAdapter.registerHalV1(mFakeHalImplV1_1);
assertThat(mHalAdapter.mDisplayOffloadV1_0).isEqualTo(mFakeHalImplV1_1);
assertThat(mHalAdapter.mDisplayOffloadV1_1).isEqualTo(mFakeHalImplV1_1);
mHalAdapter.registerHalV2(mFakeHalImplV2_0);
assertThat(mHalAdapter.mDisplayOffloadV2_0).isEqualTo(mFakeHalImplV2_0);
}
@Test
public void testHalListener() throws RemoteException {
mHalAdapter.registerHalV1(mFakeHalImplV1_1);
mHalAdapter.attachHalListener(mFakeHalListener);
// onHalRegistered should be called when service becomes available
mHalAdapter.onRegistration(
vendor.google_clockwork.displayoffload.V1_0.IDisplayOffload.kInterfaceName,
"",
true);
verify(mHalAdapter.mHalListener).onHalRegistered();
// onHalDied should be called when service dies
mHalAdapter.serviceDied(1);
verify(mHalAdapter.mHalListener).onHalDied();
}
@Test
public void testDeathRecipient() {
// Already Dead
mHalAdapter.serviceDied(1);
verify(fakeBinder1, never()).unlinkToDeath(eq(mHalAdapter));
mHalAdapter.serviceDied(0);
verify(fakeBinder1, never()).unlinkToDeath(eq(mHalAdapter));
// V1
mHalAdapter.mDisplayOffloadV1_0 = mFakeHalImplV1_1;
mHalAdapter.mDisplayOffloadV1_1 = mFakeHalImplV1_1;
mHalAdapter.serviceDied(1);
verify(fakeBinder1, times(2)).unlinkToDeath(eq(mHalAdapter));
assertThat(mHalAdapter.mDisplayOffloadV1_0).isNull();
assertThat(mHalAdapter.mDisplayOffloadV1_1).isNull();
// V2
mHalAdapter.mDisplayOffloadV2_0 = mFakeHalImplV2_0;
mHalAdapter.serviceDied(2);
verify(fakeBinder2, times(1)).unlinkToDeath(eq(mHalAdapter));
assertThat(mHalAdapter.mDisplayOffloadV2_0).isNull();
}
public void verifySendHalObject(IFakeDisplayOffloadHal mHal)
throws RemoteException, DisplayOffloadException {
for (Object o : mHal.listOfHALObjects()) {
mHalAdapter.send(o);
mHal.verifyHalInteractions(o);
}
}
interface IFakeDisplayOffloadHal {
List<Object> listOfHALObjects();
void verifyHalInteractions(Object o) throws RemoteException, DisplayOffloadException;
}
}