Merge "camera: Add OisSamples synthetic key"
diff --git a/audio/4.0/IDevice.hal b/audio/4.0/IDevice.hal
index bb58568..7eb03c8 100644
--- a/audio/4.0/IDevice.hal
+++ b/audio/4.0/IDevice.hal
@@ -268,4 +268,16 @@
*/
getMicrophones()
generates(Result retval, vec<MicrophoneInfo> microphones);
+
+ /**
+ * Notifies the device module about the connection state of an input/output
+ * device attached to it. Calling this method is equivalent to setting
+ * AUDIO_PARAMETER_DEVICE_[DIS]CONNECT on the legacy HAL.
+ *
+ * @param address audio device specification.
+ * @param connected whether the device is connected.
+ * @return retval operation completion status.
+ */
+ setConnectedState(DeviceAddress address, bool connected)
+ generates (Result retval);
};
diff --git a/audio/4.0/IPrimaryDevice.hal b/audio/4.0/IPrimaryDevice.hal
index f3d904c..258c28b 100644
--- a/audio/4.0/IPrimaryDevice.hal
+++ b/audio/4.0/IPrimaryDevice.hal
@@ -37,6 +37,17 @@
setMode(AudioMode mode) generates (Result retval);
/**
+ * Sets the name of the current BT SCO headset. Calling this method
+ * is equivalent to setting legacy "bt_headset_name" parameter.
+ * The BT SCO headset name must only be used for debugging purposes.
+ * Optional method
+ *
+ * @param name the name of the current BT SCO headset (can be empty).
+ * @return retval operation completion status.
+ */
+ setBtScoHeadsetDebugName(string name) generates (Result retval);
+
+ /**
* Gets whether BT SCO Noise Reduction and Echo Cancellation are enabled.
* Calling this method is equivalent to getting AUDIO_PARAMETER_KEY_BT_NREC
* on the legacy HAL.
@@ -76,6 +87,48 @@
*/
setBtScoWidebandEnabled(bool enabled) generates (Result retval);
+ /**
+ * Gets whether BT HFP (Hands-Free Profile) is enabled. Calling this method
+ * is equivalent to getting "hfp_enable" parameter value on the legacy HAL.
+ *
+ * @return retval operation completion status.
+ * @return enabled whether BT HFP is enabled.
+ */
+ getBtHfpEnabled() generates (Result retval, bool enabled);
+
+ /**
+ * Sets whether BT HFP (Hands-Free Profile) is enabled. Calling this method
+ * is equivalent to setting "hfp_enable" parameter on the legacy HAL.
+ * Optional method
+ *
+ * @param enabled whether BT HFP is enabled.
+ * @return retval operation completion status.
+ */
+ setBtHfpEnabled(bool enabled) generates (Result retval);
+
+ /**
+ * Sets the sampling rate of BT HFP (Hands-Free Profile). Calling this
+ * method is equivalent to setting "hfp_set_sampling_rate" parameter
+ * on the legacy HAL.
+ * Optional method
+ *
+ * @param sampleRateHz sample rate in Hz.
+ * @return retval operation completion status.
+ */
+ setBtHfpSampleRate(uint32_t sampleRateHz) generates (Result retval);
+
+ /**
+ * Sets the current output volume Hz for BT HFP (Hands-Free Profile).
+ * Calling this method is equivalent to setting "hfp_volume" parameter value
+ * on the legacy HAL (except that legacy HAL implementations expect
+ * an integer value in the range from 0 to 15.)
+ * Optional method
+ *
+ * @param volume 1.0f means unity, 0.0f is zero.
+ * @return retval operation completion status.
+ */
+ setBtHfpVolume(float volume) generates (Result retval);
+
enum TtyMode : int32_t {
OFF,
VCO,
@@ -121,4 +174,22 @@
* @return retval operation completion status.
*/
setHacEnabled(bool enabled) generates (Result retval);
+
+ enum Rotation : int32_t {
+ DEG_0,
+ DEG_90,
+ DEG_180,
+ DEG_270
+ };
+
+ /**
+ * Updates HAL on the current rotation of the device relative to natural
+ * orientation. Calling this method is equivalent to setting legacy
+ * parameter "rotation".
+ *
+ * @param rotation rotation in degrees relative to natural device
+ * orientation.
+ * @return retval operation completion status.
+ */
+ updateRotation(Rotation rotation) generates (Result retval);
};
diff --git a/audio/4.0/IStream.hal b/audio/4.0/IStream.hal
index f05d7b0..e7a4b7d 100644
--- a/audio/4.0/IStream.hal
+++ b/audio/4.0/IStream.hal
@@ -175,38 +175,26 @@
standby() generates (Result retval);
/**
- * Return the set of device(s) which this stream is connected to.
+ * Return the set of devices which this stream is connected to.
* Optional method
*
* @return retval operation completion status: OK or NOT_SUPPORTED.
- * @return device set of device(s) which this stream is connected to.
+ * @return device set of devices which this stream is connected to.
*/
- getDevice() generates (Result retval, bitfield<AudioDevice> device);
+ getDevices() generates (Result retval, vec<DeviceAddress> devices);
/**
- * Connects the stream to the device.
+ * Connects the stream to one or multiple devices.
*
* This method must only be used for HALs that do not support
* 'IDevice.createAudioPatch' method. Calling this method is
- * equivalent to setting AUDIO_PARAMETER_STREAM_ROUTING in the legacy HAL
- * interface.
+ * equivalent to setting AUDIO_PARAMETER_STREAM_ROUTING preceeded
+ * with a device address in the legacy HAL interface.
*
* @param address device to connect the stream to.
* @return retval operation completion status.
*/
- setDevice(DeviceAddress address) generates (Result retval);
-
- /**
- * Notifies the stream about device connection state. Calling this method is
- * equivalent to setting AUDIO_PARAMETER_DEVICE_[DIS]CONNECT on the legacy
- * HAL.
- *
- * @param address audio device specification.
- * @param connected whether the device is connected.
- * @return retval operation completion status.
- */
- setConnectedState(DeviceAddress address, bool connected)
- generates (Result retval);
+ setDevices(vec<DeviceAddress> devices) generates (Result retval);
/**
* Sets the HW synchronization source. Calling this method is equivalent to
diff --git a/audio/4.0/IStreamOut.hal b/audio/4.0/IStreamOut.hal
index 3aa93fc..65eba60 100644
--- a/audio/4.0/IStreamOut.hal
+++ b/audio/4.0/IStreamOut.hal
@@ -264,4 +264,16 @@
*/
getPresentationPosition()
generates (Result retval, uint64_t frames, TimeSpec timeStamp);
+
+ /**
+ * Selects a presentation for decoding from a next generation media stream
+ * (as defined per ETSI TS 103 190-2) and a program within the presentation.
+ * Optional method
+ *
+ * @param presentationId selected audio presentation.
+ * @param programId refinement for the presentation.
+ * @return retval operation completion status.
+ */
+ selectPresentation(int32_t presentationId, int32_t programId)
+ generates (Result retval);
};
diff --git a/audio/4.0/types.hal b/audio/4.0/types.hal
index 7853f3c..7b2035b 100644
--- a/audio/4.0/types.hal
+++ b/audio/4.0/types.hal
@@ -23,6 +23,10 @@
NOT_INITIALIZED,
INVALID_ARGUMENTS,
INVALID_STATE,
+ /**
+ * Methods marked as "Optional method" must return this result value
+ * if the operation is not supported by HAL.
+ */
NOT_SUPPORTED
};
diff --git a/audio/common/4.0/types.hal b/audio/common/4.0/types.hal
index d4c6efe..4efdea3 100644
--- a/audio/common/4.0/types.hal
+++ b/audio/common/4.0/types.hal
@@ -485,7 +485,7 @@
};
@export(name="", value_prefix="AUDIO_DEVICE_")
-enum AudioDevice : uint64_t {
+enum AudioDevice : uint32_t {
NONE = 0x0,
/** reserved bits */
BIT_IN = 0x80000000,
@@ -530,6 +530,7 @@
OUT_BUS = 0x1000000,
OUT_PROXY = 0x2000000,
OUT_USB_HEADSET = 0x4000000,
+ OUT_HEARING_AID = 0x8000000,
OUT_ECHO_CANCELLER = 0x10000000,
OUT_DEFAULT = BIT_DEFAULT,
// Note that the 2.0 OUT_ALL* have been moved to helper functions
diff --git a/authsecret/1.0/IAuthSecret.hal b/authsecret/1.0/IAuthSecret.hal
index 6b573b3..9a0fd5f 100644
--- a/authsecret/1.0/IAuthSecret.hal
+++ b/authsecret/1.0/IAuthSecret.hal
@@ -42,5 +42,5 @@
*
* @param secret blob derived from the primary user's credential.
*/
- primaryUserCredential(vec<uint8_t> secret);
+ oneway primaryUserCredential(vec<uint8_t> secret);
};
diff --git a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
index 57050d7..d904ad0 100644
--- a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
+++ b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
@@ -54,7 +54,7 @@
#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
#include <VtsHalHidlTargetTestBase.h>
-
+#include <VtsHalHidlTargetTestEnvBase.h>
using namespace ::android::hardware::automotive::evs::V1_0;
using ::android::hardware::Return;
@@ -64,13 +64,28 @@
using ::android::hardware::hidl_string;
using ::android::sp;
+// Test environment for Evs HIDL HAL.
+class EvsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static EvsHidlEnvironment* Instance() {
+ static EvsHidlEnvironment* instance = new EvsHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<IEvsEnumerator>(); }
+
+ private:
+ EvsHidlEnvironment() {}
+};
// The main test class for EVS
class EvsHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
virtual void SetUp() override {
// Make sure we can connect to the enumerator
- pEnumerator = IEvsEnumerator::getService(kEnumeratorName);
+ pEnumerator = getService<IEvsEnumerator>(
+ EvsHidlEnvironment::Instance()->getServiceName<IEvsEnumerator>(kEnumeratorName));
ASSERT_NE(pEnumerator.get(), nullptr);
}
@@ -480,3 +495,12 @@
// Explicitly release the display
pEnumerator->closeDisplay(pDisplay);
}
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ EvsHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/broadcastradio/1.0/vts/functional/Android.bp b/broadcastradio/1.0/vts/functional/Android.bp
index f31a2dc..7040a01 100644
--- a/broadcastradio/1.0/vts/functional/Android.bp
+++ b/broadcastradio/1.0/vts/functional/Android.bp
@@ -18,5 +18,8 @@
name: "VtsHalBroadcastradioV1_0TargetTest",
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalBroadcastradioV1_0TargetTest.cpp"],
- static_libs: ["android.hardware.broadcastradio@1.0"],
+ static_libs: [
+ "android.hardware.broadcastradio@1.0",
+ "android.hardware.broadcastradio@vts-utils-lib",
+ ],
}
diff --git a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
index fd048db..90c8463 100644
--- a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
+++ b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
@@ -22,12 +22,12 @@
#include <hidl/HidlTransportSupport.h>
#include <utils/threads.h>
-#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h>
+#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
#include <android/hardware/broadcastradio/1.0/ITuner.h>
#include <android/hardware/broadcastradio/1.0/ITunerCallback.h>
#include <android/hardware/broadcastradio/1.0/types.h>
-
+#include <broadcastradio-vts-utils/environment-utils.h>
using ::android::sp;
using ::android::Mutex;
@@ -48,6 +48,7 @@
using ::android::hardware::broadcastradio::V1_0::MetaData;
using ::android::hardware::broadcastradio::V1_0::MetadataKey;
using ::android::hardware::broadcastradio::V1_0::MetadataType;
+using ::android::hardware::broadcastradio::vts::BroadcastRadioHidlEnvironment;
#define RETURN_IF_SKIPPED \
if (skipped) { \
@@ -55,8 +56,8 @@
return; \
}
+static BroadcastRadioHidlEnvironment<IBroadcastRadioFactory>* gEnv = nullptr;
// The main test class for Broadcast Radio HIDL HAL.
-
class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetTestBase,
public ::testing::WithParamInterface<Class> {
protected:
@@ -67,7 +68,7 @@
skipped = false;
sp<IBroadcastRadioFactory> factory =
- ::testing::VtsHalHidlTargetTestBase::getService<IBroadcastRadioFactory>();
+ getService<IBroadcastRadioFactory>(gEnv->getServiceName<IBroadcastRadioFactory>());
ASSERT_NE(nullptr, factory.get());
Result connectResult;
@@ -731,8 +732,11 @@
::testing::Values(Class::AM_FM, Class::SAT, Class::DT));
int main(int argc, char** argv) {
- ::testing::InitGoogleTest(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
+ gEnv = new BroadcastRadioHidlEnvironment<IBroadcastRadioFactory>;
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ gEnv->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
}
diff --git a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
index 823d14c..6687731 100644
--- a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
+++ b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
@@ -25,6 +25,7 @@
#include <android/hardware/broadcastradio/1.1/types.h>
#include <broadcastradio-utils-1x/Utils.h>
#include <broadcastradio-vts-utils/call-barrier.h>
+#include <broadcastradio-vts-utils/environment-utils.h>
#include <broadcastradio-vts-utils/mock-timeout.h>
#include <broadcastradio-vts-utils/pointer-utils.h>
#include <cutils/native_handle.h>
@@ -58,6 +59,7 @@
using V1_0::MetadataType;
using broadcastradio::vts::clearAndWait;
+using broadcastradio::vts::BroadcastRadioHidlEnvironment;
static constexpr auto kConfigTimeout = 10s;
static constexpr auto kConnectModuleTimeout = 1s;
@@ -91,6 +93,8 @@
MOCK_TIMEOUT_METHOD1(currentProgramInfoChanged, Return<void>(const ProgramInfo&));
};
+static BroadcastRadioHidlEnvironment<IBroadcastRadioFactory>* gEnv = nullptr;
+
class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase,
public ::testing::WithParamInterface<Class> {
protected:
@@ -119,7 +123,8 @@
radioClass = GetParam();
// lookup HIDL service
- auto factory = getService<IBroadcastRadioFactory>();
+ auto factory =
+ getService<IBroadcastRadioFactory>(gEnv->getServiceName<IBroadcastRadioFactory>());
ASSERT_NE(nullptr, factory.get());
// connect radio module
@@ -606,8 +611,14 @@
} // namespace android
int main(int argc, char** argv) {
- ::testing::InitGoogleTest(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
+ using android::hardware::broadcastradio::V1_1::vts::gEnv;
+ using android::hardware::broadcastradio::V1_1::IBroadcastRadioFactory;
+ using android::hardware::broadcastradio::vts::BroadcastRadioHidlEnvironment;
+ gEnv = new BroadcastRadioHidlEnvironment<IBroadcastRadioFactory>;
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ gEnv->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
}
diff --git a/broadcastradio/2.0/types.hal b/broadcastradio/2.0/types.hal
index 9fd0738..a9b9600 100644
--- a/broadcastradio/2.0/types.hal
+++ b/broadcastradio/2.0/types.hal
@@ -288,6 +288,9 @@
struct ProgramInfo {
/**
* An identifier used to point at the program (primarily to tune to it).
+ *
+ * This field is required - its type field must not be set to
+ * IdentifierType::INVALID.
*/
ProgramSelector selector;
@@ -302,8 +305,9 @@
* may choose to use DAB technology to make actual tuning. This identifier
* must reflect that.
*
- * This field is optional, but must be set for currently tuned program.
- * If it's not set, its value must be initialized to all-zeros.
+ * This field is required for currently tuned program only.
+ * For all other items on the program list, its type field must be
+ * initialized to IdentifierType::INVALID.
*
* Only primary identifiers for a given radio technology are valid:
* - AMFM_FREQUENCY for analog AM/FM;
@@ -326,9 +330,9 @@
* multiple ensembles. This identifier points to the channel to which the
* radio hardware is physically tuned to.
*
- * This field is optional, but must be set for currently tuned program.
- * If it's not set, its type field must be initialized to
- * IdentifierType::INVALID.
+ * This field is required for currently tuned program only.
+ * For all other items on the program list, its type field must be
+ * initialized to IdentifierType::INVALID.
*
* Only physical identifiers are valid:
* - AMFM_FREQUENCY;
@@ -408,6 +412,8 @@
* Tuned to a program (not playing a static).
*
* It's the same condition that would stop scan() operation.
+ *
+ * By definition, this flag must be set for all items on the program list.
*/
TUNED = 1 << 4,
diff --git a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
index 2a5ec8fe..6877f07 100644
--- a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
+++ b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
@@ -26,6 +26,7 @@
#include <android/hardware/broadcastradio/2.0/types.h>
#include <broadcastradio-utils-2x/Utils.h>
#include <broadcastradio-vts-utils/call-barrier.h>
+#include <broadcastradio-vts-utils/environment-utils.h>
#include <broadcastradio-vts-utils/mock-timeout.h>
#include <broadcastradio-vts-utils/pointer-utils.h>
#include <cutils/bitops.h>
@@ -52,6 +53,7 @@
using testing::Invoke;
using testing::SaveArg;
+using broadcastradio::vts::BroadcastRadioHidlEnvironment;
using broadcastradio::vts::CallBarrier;
using broadcastradio::vts::clearAndWait;
using utils::make_identifier;
@@ -97,6 +99,8 @@
MOCK_METHOD1(onListUpdated, Return<void>(const hidl_vec<Announcement>&));
};
+static BroadcastRadioHidlEnvironment<IBroadcastRadio>* gEnv = nullptr;
+
class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase {
protected:
virtual void SetUp() override;
@@ -171,7 +175,7 @@
EXPECT_EQ(nullptr, mModule.get()) << "Module is already open";
// lookup HIDL service (radio module)
- mModule = getService<IBroadcastRadio>();
+ mModule = getService<IBroadcastRadio>(gEnv->getServiceName<IBroadcastRadio>());
ASSERT_NE(nullptr, mModule.get()) << "Couldn't find broadcast radio HAL implementation";
// get module properties
@@ -804,7 +808,13 @@
} // namespace android
int main(int argc, char** argv) {
+ using android::hardware::broadcastradio::V2_0::vts::gEnv;
+ using android::hardware::broadcastradio::V2_0::IBroadcastRadio;
+ using android::hardware::broadcastradio::vts::BroadcastRadioHidlEnvironment;
+ gEnv = new BroadcastRadioHidlEnvironment<IBroadcastRadio>;
+ ::testing::AddGlobalTestEnvironment(gEnv);
::testing::InitGoogleTest(&argc, argv);
+ gEnv->init(&argc, argv);
int status = RUN_ALL_TESTS();
ALOGI("Test result = %d", status);
return status;
diff --git a/broadcastradio/common/vts/utils/Android.bp b/broadcastradio/common/vts/utils/Android.bp
index 4ba8a17..d3edc76 100644
--- a/broadcastradio/common/vts/utils/Android.bp
+++ b/broadcastradio/common/vts/utils/Android.bp
@@ -25,4 +25,8 @@
"-Wextra",
"-Werror",
],
+ static_libs: [
+ "VtsHalHidlTargetTestBase",
+ ],
+ group_static_libs: true,
}
diff --git a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/environment-utils.h b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/environment-utils.h
new file mode 100644
index 0000000..274e632
--- /dev/null
+++ b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/environment-utils.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_VTS_ENVIRONMENT_UTILS
+#define ANDROID_HARDWARE_BROADCASTRADIO_VTS_ENVIRONMENT_UTILS
+
+#include <VtsHalHidlTargetTestEnvBase.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace vts {
+
+// Test environment for BroadcastRadio HIDL HAL.
+template <typename... T>
+class BroadcastRadioHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ virtual void registerTestServices() override {
+ using expander = int[];
+ (void)expander{0, (registerTestService<T>(), 0)...};
+ }
+};
+
+} // namespace vts
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_VTS_ENVIRONMENT_UTILS
diff --git a/camera/device/3.4/default/CameraDeviceSession.cpp b/camera/device/3.4/default/CameraDeviceSession.cpp
index 771197a..bb4886d 100644
--- a/camera/device/3.4/default/CameraDeviceSession.cpp
+++ b/camera/device/3.4/default/CameraDeviceSession.cpp
@@ -370,7 +370,7 @@
for (size_t i = 0; i < settingsCount; i++) {
uint64_t settingsSize = request.physicalCameraSettings[i].fmqSettingsSize;
- const camera_metadata_t *settings;
+ const camera_metadata_t *settings = nullptr;
if (settingsSize > 0) {
physicalFmq.push_back(V3_2::CameraMetadata(settingsSize));
bool read = mRequestMetadataQueue->read(physicalFmq[i].data(), settingsSize);
@@ -392,6 +392,13 @@
ALOGE("%s: physical camera settings metadata is corrupt!", __FUNCTION__);
return Status::ILLEGAL_ARGUMENT;
}
+
+ if (mFirstRequest && settings == nullptr) {
+ ALOGE("%s: Individual request settings must not be null for first request!",
+ __FUNCTION__);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
physicalCameraIds.push_back(request.physicalCameraSettings[i].physicalCameraId.c_str());
}
}
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index 61b8921..14f82bc 100644
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -131,7 +131,7 @@
session = new ExternalCameraDeviceSession(
callback, mCfg, mSupportedFormats, mCroppingType,
- mCameraCharacteristics, std::move(fd));
+ mCameraCharacteristics, mCameraId, std::move(fd));
if (session == nullptr) {
ALOGE("%s: camera device session allocation failed", __FUNCTION__);
mLock.unlock();
@@ -595,16 +595,19 @@
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
}
- int64_t min_frame_duration = std::numeric_limits<int64_t>::max();
- for (const auto& frameRate : supportedFormat.frameRates) {
- int64_t frame_duration = 1000000000LL / frameRate;
- if (frame_duration < min_frame_duration) {
- min_frame_duration = frame_duration;
+ int64_t minFrameDuration = std::numeric_limits<int64_t>::max();
+ for (const auto& fr : supportedFormat.frameRates) {
+ // 1000000000LL < (2^32 - 1) and
+ // fr.durationNumerator is uint32_t, so no overflow here
+ int64_t frameDuration = 1000000000LL * fr.durationNumerator /
+ fr.durationDenominator;
+ if (frameDuration < minFrameDuration) {
+ minFrameDuration = frameDuration;
}
- if (frame_duration > maxFrameDuration) {
- maxFrameDuration = frame_duration;
+ if (frameDuration > maxFrameDuration) {
+ maxFrameDuration = frameDuration;
}
- int32_t frameRateInt = static_cast<int32_t>(frameRate);
+ int32_t frameRateInt = static_cast<int32_t>(fr.getDouble());
if (minFps > frameRateInt) {
minFps = frameRateInt;
}
@@ -618,7 +621,7 @@
minFrameDurations.push_back(format);
minFrameDurations.push_back(supportedFormat.width);
minFrameDurations.push_back(supportedFormat.height);
- minFrameDurations.push_back(min_frame_duration);
+ minFrameDurations.push_back(minFrameDuration);
}
// The stall duration is 0 for non-jpeg formats. For JPEG format, stall
@@ -705,8 +708,10 @@
++frameInterval.index) {
if (frameInterval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
if (frameInterval.discrete.numerator != 0) {
- float framerate = frameInterval.discrete.denominator /
- static_cast<float>(frameInterval.discrete.numerator);
+ SupportedV4L2Format::FrameRate fr = {
+ frameInterval.discrete.numerator,
+ frameInterval.discrete.denominator};
+ double framerate = fr.getDouble();
if (framerate > fpsUpperBound) {
continue;
}
@@ -717,7 +722,7 @@
(frameInterval.pixel_format >> 16) & 0xFF,
(frameInterval.pixel_format >> 24) & 0xFF,
frameInterval.width, frameInterval.height, framerate);
- format->frameRates.push_back(framerate);
+ format->frameRates.push_back(fr);
}
}
}
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index b6728ed..5346f80 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -46,6 +46,21 @@
// bad frames. TODO: develop a better bad frame detection
// method
+bool tryLock(Mutex& mutex)
+{
+ static const int kDumpLockRetries = 50;
+ static const int kDumpLockSleep = 60000;
+ bool locked = false;
+ for (int i = 0; i < kDumpLockRetries; ++i) {
+ if (mutex.tryLock() == NO_ERROR) {
+ locked = true;
+ break;
+ }
+ usleep(kDumpLockSleep);
+ }
+ return locked;
+}
+
} // Anonymous namespace
// Static instances
@@ -59,12 +74,14 @@
const std::vector<SupportedV4L2Format>& sortedFormats,
const CroppingType& croppingType,
const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId,
unique_fd v4l2Fd) :
mCallback(callback),
mCfg(cfg),
mCameraCharacteristics(chars),
mSupportedFormats(sortedFormats),
mCroppingType(croppingType),
+ mCameraId(cameraId),
mV4l2Fd(std::move(v4l2Fd)),
mOutputThread(new OutputThread(this, mCroppingType)),
mMaxThumbResolution(getMaxThumbResolution()),
@@ -119,8 +136,79 @@
}
}
-void ExternalCameraDeviceSession::dumpState(const native_handle_t*) {
- // TODO: b/72261676 dump more runtime information
+
+void ExternalCameraDeviceSession::dumpState(const native_handle_t* handle) {
+ if (handle->numFds != 1 || handle->numInts != 0) {
+ ALOGE("%s: handle must contain 1 FD and 0 integers! Got %d FDs and %d ints",
+ __FUNCTION__, handle->numFds, handle->numInts);
+ return;
+ }
+ int fd = handle->data[0];
+
+ bool intfLocked = tryLock(mInterfaceLock);
+ if (!intfLocked) {
+ dprintf(fd, "!! ExternalCameraDeviceSession interface may be deadlocked !!\n");
+ }
+
+ if (isClosed()) {
+ dprintf(fd, "External camera %s is closed\n", mCameraId.c_str());
+ return;
+ }
+
+ bool streaming = false;
+ size_t v4L2BufferCount = 0;
+ SupportedV4L2Format streamingFmt;
+ std::unordered_set<uint32_t> inflightFrames;
+ {
+ Mutex::Autolock _l(mLock);
+ bool sessionLocked = tryLock(mLock);
+ if (!sessionLocked) {
+ dprintf(fd, "!! ExternalCameraDeviceSession mLock may be deadlocked !!\n");
+ }
+ streaming = mV4l2Streaming;
+ streamingFmt = mV4l2StreamingFmt;
+ v4L2BufferCount = mV4L2BufferCount;
+ inflightFrames = mInflightFrames;
+ if (sessionLocked) {
+ mLock.unlock();
+ }
+ }
+
+ dprintf(fd, "External camera %s V4L2 FD %d, cropping type %s, %s\n",
+ mCameraId.c_str(), mV4l2Fd.get(),
+ (mCroppingType == VERTICAL) ? "vertical" : "horizontal",
+ streaming ? "streaming" : "not streaming");
+ if (streaming) {
+ // TODO: dump fps later
+ dprintf(fd, "Current V4L2 format %c%c%c%c %dx%d\n",
+ streamingFmt.fourcc & 0xFF,
+ (streamingFmt.fourcc >> 8) & 0xFF,
+ (streamingFmt.fourcc >> 16) & 0xFF,
+ (streamingFmt.fourcc >> 24) & 0xFF,
+ streamingFmt.width, streamingFmt.height);
+
+ size_t numDequeuedV4l2Buffers = 0;
+ {
+ std::lock_guard<std::mutex> lk(mV4l2BufferLock);
+ numDequeuedV4l2Buffers = mNumDequeuedV4l2Buffers;
+ }
+ dprintf(fd, "V4L2 buffer queue size %zu, dequeued %zu\n",
+ v4L2BufferCount, numDequeuedV4l2Buffers);
+ }
+
+ dprintf(fd, "In-flight frames (not sorted):");
+ for (const auto& frameNumber : inflightFrames) {
+ dprintf(fd, "%d, ", frameNumber);
+ }
+ dprintf(fd, "\n");
+ mOutputThread->dump(fd);
+ dprintf(fd, "\n");
+
+ if (intfLocked) {
+ mInterfaceLock.unlock();
+ }
+
+ return;
}
Return<void> ExternalCameraDeviceSession::constructDefaultRequestSettings(
@@ -270,26 +358,31 @@
}
Return<Status> ExternalCameraDeviceSession::flush() {
+ Mutex::Autolock _il(mInterfaceLock);
+ Status status = initStatus();
+ if (status != Status::OK) {
+ return status;
+ }
+ mOutputThread->flush();
return Status::OK;
}
Return<void> ExternalCameraDeviceSession::close() {
Mutex::Autolock _il(mInterfaceLock);
- Mutex::Autolock _l(mLock);
- if (!mClosed) {
- // TODO: b/72261676 Cleanup inflight buffers/V4L2 buffer queue
+ bool closed = isClosed();
+ if (!closed) {
+ mOutputThread->flush();
+ mOutputThread->requestExit();
+ mOutputThread->join();
+
+ Mutex::Autolock _l(mLock);
+ // free all buffers
+ for(auto pair : mStreamMap) {
+ cleanupBuffersLocked(/*Stream ID*/pair.first);
+ }
+ v4l2StreamOffLocked();
ALOGV("%s: closing V4L2 camera FD %d", __FUNCTION__, mV4l2Fd.get());
mV4l2Fd.reset();
- mOutputThread->requestExit(); // TODO: join?
-
- // free all imported buffers
- for(auto& pair : mCirculatingBuffers) {
- CirculatingBuffers& buffers = pair.second;
- for (auto& p2 : buffers) {
- sHandleImporter.freeBuffer(p2.second);
- }
- }
-
mClosed = true;
}
return Void();
@@ -425,25 +518,22 @@
// TODO: program fps range per capture request here
// or limit the set of availableFpsRange
- sp<V4L2Frame> frameIn = dequeueV4l2FrameLocked();
+
+ nsecs_t shutterTs = 0;
+ sp<V4L2Frame> frameIn = dequeueV4l2FrameLocked(&shutterTs);
if ( frameIn == nullptr) {
ALOGE("%s: V4L2 deque frame failed!", __FUNCTION__);
return Status::INTERNAL_ERROR;
}
- // TODO: This can probably be replaced by use v4lbuffer timestamp
- // if the device supports it
- nsecs_t shutterTs = systemTime(SYSTEM_TIME_MONOTONIC);
-
- // TODO: reduce object copy in this path
- HalRequest halReq = {
- .frameNumber = request.frameNumber,
- .setting = mLatestReqSetting,
- .frameIn = frameIn,
- .shutterTs = shutterTs};
- halReq.buffers.resize(numOutputBufs);
+ std::shared_ptr<HalRequest> halReq = std::make_shared<HalRequest>();
+ halReq->frameNumber = request.frameNumber;
+ halReq->setting = mLatestReqSetting;
+ halReq->frameIn = frameIn;
+ halReq->shutterTs = shutterTs;
+ halReq->buffers.resize(numOutputBufs);
for (size_t i = 0; i < numOutputBufs; i++) {
- HalStreamBuffer& halBuf = halReq.buffers[i];
+ HalStreamBuffer& halBuf = halReq->buffers[i];
int streamId = halBuf.streamId = request.outputBuffers[i].streamId;
halBuf.bufferId = request.outputBuffers[i].bufferId;
const Stream& stream = mStreamMap[streamId];
@@ -455,7 +545,7 @@
halBuf.acquireFence = allFences[i];
halBuf.fenceTimeout = false;
}
- mInflightFrames.insert(halReq.frameNumber);
+ mInflightFrames.insert(halReq->frameNumber);
// Send request to OutputThread for the rest of processing
mOutputThread->submitRequest(halReq);
mFirstRequest = false;
@@ -481,30 +571,31 @@
}
//TODO: refactor with processCaptureResult
-Status ExternalCameraDeviceSession::processCaptureRequestError(HalRequest& req) {
+Status ExternalCameraDeviceSession::processCaptureRequestError(
+ const std::shared_ptr<HalRequest>& req) {
// Return V4L2 buffer to V4L2 buffer queue
- enqueueV4l2Frame(req.frameIn);
+ enqueueV4l2Frame(req->frameIn);
// NotifyShutter
- notifyShutter(req.frameNumber, req.shutterTs);
+ notifyShutter(req->frameNumber, req->shutterTs);
- notifyError(/*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+ notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
// Fill output buffers
hidl_vec<CaptureResult> results;
results.resize(1);
CaptureResult& result = results[0];
- result.frameNumber = req.frameNumber;
+ result.frameNumber = req->frameNumber;
result.partialResult = 1;
result.inputBuffer.streamId = -1;
- result.outputBuffers.resize(req.buffers.size());
- for (size_t i = 0; i < req.buffers.size(); i++) {
- result.outputBuffers[i].streamId = req.buffers[i].streamId;
- result.outputBuffers[i].bufferId = req.buffers[i].bufferId;
+ result.outputBuffers.resize(req->buffers.size());
+ for (size_t i = 0; i < req->buffers.size(); i++) {
+ result.outputBuffers[i].streamId = req->buffers[i].streamId;
+ result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
result.outputBuffers[i].status = BufferStatus::ERROR;
- if (req.buffers[i].acquireFence >= 0) {
+ if (req->buffers[i].acquireFence >= 0) {
native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
- handle->data[0] = req.buffers[i].acquireFence;
+ handle->data[0] = req->buffers[i].acquireFence;
result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
}
}
@@ -512,7 +603,7 @@
// update inflight records
{
Mutex::Autolock _l(mLock);
- mInflightFrames.erase(req.frameNumber);
+ mInflightFrames.erase(req->frameNumber);
}
// Callback into framework
@@ -521,51 +612,51 @@
return Status::OK;
}
-Status ExternalCameraDeviceSession::processCaptureResult(HalRequest& req) {
+Status ExternalCameraDeviceSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
// Return V4L2 buffer to V4L2 buffer queue
- enqueueV4l2Frame(req.frameIn);
+ enqueueV4l2Frame(req->frameIn);
// NotifyShutter
- notifyShutter(req.frameNumber, req.shutterTs);
+ notifyShutter(req->frameNumber, req->shutterTs);
// Fill output buffers
hidl_vec<CaptureResult> results;
results.resize(1);
CaptureResult& result = results[0];
- result.frameNumber = req.frameNumber;
+ result.frameNumber = req->frameNumber;
result.partialResult = 1;
result.inputBuffer.streamId = -1;
- result.outputBuffers.resize(req.buffers.size());
- for (size_t i = 0; i < req.buffers.size(); i++) {
- result.outputBuffers[i].streamId = req.buffers[i].streamId;
- result.outputBuffers[i].bufferId = req.buffers[i].bufferId;
- if (req.buffers[i].fenceTimeout) {
+ result.outputBuffers.resize(req->buffers.size());
+ for (size_t i = 0; i < req->buffers.size(); i++) {
+ result.outputBuffers[i].streamId = req->buffers[i].streamId;
+ result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
+ if (req->buffers[i].fenceTimeout) {
result.outputBuffers[i].status = BufferStatus::ERROR;
native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
- handle->data[0] = req.buffers[i].acquireFence;
+ handle->data[0] = req->buffers[i].acquireFence;
result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
- notifyError(req.frameNumber, req.buffers[i].streamId, ErrorCode::ERROR_BUFFER);
+ notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
} else {
result.outputBuffers[i].status = BufferStatus::OK;
// TODO: refactor
- if (req.buffers[i].acquireFence > 0) {
+ if (req->buffers[i].acquireFence > 0) {
native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
- handle->data[0] = req.buffers[i].acquireFence;
+ handle->data[0] = req->buffers[i].acquireFence;
result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
}
}
}
// Fill capture result metadata
- fillCaptureResult(req.setting, req.shutterTs);
- const camera_metadata_t *rawResult = req.setting.getAndLock();
+ fillCaptureResult(req->setting, req->shutterTs);
+ const camera_metadata_t *rawResult = req->setting.getAndLock();
V3_2::implementation::convertToHidl(rawResult, &result.result);
- req.setting.unlock(rawResult);
+ req->setting.unlock(rawResult);
// update inflight records
{
Mutex::Autolock _l(mLock);
- mInflightFrames.erase(req.frameNumber);
+ mInflightFrames.erase(req->frameNumber);
}
// Callback into framework
@@ -1296,7 +1387,7 @@
int ExternalCameraDeviceSession::OutputThread::createJpegLocked(
HalStreamBuffer &halBuf,
- HalRequest &req)
+ const std::shared_ptr<HalRequest>& req)
{
int ret;
auto lfail = [&](auto... args) {
@@ -1323,17 +1414,17 @@
int jpegQuality, thumbQuality;
Size thumbSize;
- if (req.setting.exists(ANDROID_JPEG_QUALITY)) {
+ if (req->setting.exists(ANDROID_JPEG_QUALITY)) {
camera_metadata_entry entry =
- req.setting.find(ANDROID_JPEG_QUALITY);
+ req->setting.find(ANDROID_JPEG_QUALITY);
jpegQuality = entry.data.u8[0];
} else {
return lfail("%s: ANDROID_JPEG_QUALITY not set",__FUNCTION__);
}
- if (req.setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
+ if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
camera_metadata_entry entry =
- req.setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
+ req->setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
thumbQuality = entry.data.u8[0];
} else {
return lfail(
@@ -1341,9 +1432,9 @@
__FUNCTION__);
}
- if (req.setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
+ if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
camera_metadata_entry entry =
- req.setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
+ req->setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
thumbSize = Size { static_cast<uint32_t>(entry.data.i32[0]),
static_cast<uint32_t>(entry.data.i32[1])
};
@@ -1403,7 +1494,7 @@
/* Combine camera characteristics with request settings to form EXIF
* metadata */
common::V1_0::helper::CameraMetadata meta(parent->mCameraCharacteristics);
- meta.append(req.setting);
+ meta.append(req->setting);
/* Generate EXIF object */
std::unique_ptr<ExifUtils> utils(ExifUtils::create());
@@ -1467,7 +1558,7 @@
}
bool ExternalCameraDeviceSession::OutputThread::threadLoop() {
- HalRequest req;
+ std::shared_ptr<HalRequest> req;
auto parent = mParent.promote();
if (parent == nullptr) {
ALOGE("%s: session has been disconnected!", __FUNCTION__);
@@ -1478,29 +1569,33 @@
// regularly to prevent v4l buffer queue filled with stale buffers
// when app doesn't program a preveiw request
waitForNextRequest(&req);
- if (req.frameIn == nullptr) {
+ if (req == nullptr) {
// No new request, wait again
return true;
}
- if (req.frameIn->mFourcc != V4L2_PIX_FMT_MJPEG) {
- ALOGE("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__,
- req.frameIn->mFourcc & 0xFF,
- (req.frameIn->mFourcc >> 8) & 0xFF,
- (req.frameIn->mFourcc >> 16) & 0xFF,
- (req.frameIn->mFourcc >> 24) & 0xFF);
+ auto onDeviceError = [&](auto... args) {
+ ALOGE(args...);
parent->notifyError(
- /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
+ req->frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
+ signalRequestDone();
return false;
+ };
+
+ if (req->frameIn->mFourcc != V4L2_PIX_FMT_MJPEG) {
+ return onDeviceError("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__,
+ req->frameIn->mFourcc & 0xFF,
+ (req->frameIn->mFourcc >> 8) & 0xFF,
+ (req->frameIn->mFourcc >> 16) & 0xFF,
+ (req->frameIn->mFourcc >> 24) & 0xFF);
}
- std::unique_lock<std::mutex> lk(mLock);
-
+ std::unique_lock<std::mutex> lk(mBufferLock);
// Convert input V4L2 frame to YU12 of the same size
// TODO: see if we can save some computation by converting to YV12 here
uint8_t* inData;
size_t inDataSize;
- req.frameIn->map(&inData, &inDataSize);
+ req->frameIn->map(&inData, &inDataSize);
// TODO: profile
// TODO: in some special case maybe we can decode jpg directly to gralloc output?
int res = libyuv::MJPGToI420(
@@ -1520,17 +1615,15 @@
lk.unlock();
Status st = parent->processCaptureRequestError(req);
if (st != Status::OK) {
- ALOGE("%s: failed to process capture request error!", __FUNCTION__);
- parent->notifyError(
- /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
- return false;
+ return onDeviceError("%s: failed to process capture request error!", __FUNCTION__);
}
+ signalRequestDone();
return true;
}
ALOGV("%s processing new request", __FUNCTION__);
const int kSyncWaitTimeoutMs = 500;
- for (auto& halBuf : req.buffers) {
+ for (auto& halBuf : req->buffers) {
if (halBuf.acquireFence != -1) {
int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs);
if (ret) {
@@ -1551,15 +1644,9 @@
int ret = createJpegLocked(halBuf, req);
if(ret != 0) {
- ALOGE("%s: createJpegLocked failed with %d",
- __FUNCTION__, ret);
lk.unlock();
- parent->notifyError(
- /*frameNum*/req.frameNumber,
- /*stream*/-1,
- ErrorCode::ERROR_DEVICE);
-
- return false;
+ return onDeviceError("%s: createJpegLocked failed with %d",
+ __FUNCTION__, ret);
}
} break;
case PixelFormat::YCBCR_420_888:
@@ -1587,21 +1674,15 @@
Size { halBuf.width, halBuf.height },
&cropAndScaled);
if (ret != 0) {
- ALOGE("%s: crop and scale failed!", __FUNCTION__);
lk.unlock();
- parent->notifyError(
- /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
- return false;
+ return onDeviceError("%s: crop and scale failed!", __FUNCTION__);
}
Size sz {halBuf.width, halBuf.height};
ret = formatConvertLocked(cropAndScaled, outLayout, sz, outputFourcc);
if (ret != 0) {
- ALOGE("%s: format coversion failed!", __FUNCTION__);
lk.unlock();
- parent->notifyError(
- /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
- return false;
+ return onDeviceError("%s: format coversion failed!", __FUNCTION__);
}
int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
if (relFence > 0) {
@@ -1609,11 +1690,8 @@
}
} break;
default:
- ALOGE("%s: unknown output format %x", __FUNCTION__, halBuf.format);
lk.unlock();
- parent->notifyError(
- /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
- return false;
+ return onDeviceError("%s: unknown output format %x", __FUNCTION__, halBuf.format);
}
} // for each buffer
mScaledYu12Frames.clear();
@@ -1622,18 +1700,16 @@
lk.unlock();
Status st = parent->processCaptureResult(req);
if (st != Status::OK) {
- ALOGE("%s: failed to process capture result!", __FUNCTION__);
- parent->notifyError(
- /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
- return false;
+ return onDeviceError("%s: failed to process capture result!", __FUNCTION__);
}
+ signalRequestDone();
return true;
}
Status ExternalCameraDeviceSession::OutputThread::allocateIntermediateBuffers(
const Size& v4lSize, const Size& thumbSize,
const hidl_vec<Stream>& streams) {
- std::lock_guard<std::mutex> lk(mLock);
+ std::lock_guard<std::mutex> lk(mBufferLock);
if (mScaledYu12Frames.size() != 0) {
ALOGE("%s: intermediate buffer pool has %zu inflight buffers! (expect 0)",
__FUNCTION__, mScaledYu12Frames.size());
@@ -1704,37 +1780,88 @@
return Status::OK;
}
-Status ExternalCameraDeviceSession::OutputThread::submitRequest(const HalRequest& req) {
- std::lock_guard<std::mutex> lk(mLock);
- // TODO: reduce object copy in this path
+Status ExternalCameraDeviceSession::OutputThread::submitRequest(
+ const std::shared_ptr<HalRequest>& req) {
+ std::unique_lock<std::mutex> lk(mRequestListLock);
mRequestList.push_back(req);
+ lk.unlock();
mRequestCond.notify_one();
return Status::OK;
}
void ExternalCameraDeviceSession::OutputThread::flush() {
- std::lock_guard<std::mutex> lk(mLock);
- // TODO: send buffer/request errors back to framework
+ auto parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("%s: session has been disconnected!", __FUNCTION__);
+ return;
+ }
+
+ std::unique_lock<std::mutex> lk(mRequestListLock);
+ std::list<std::shared_ptr<HalRequest>> reqs = std::move(mRequestList);
mRequestList.clear();
+ if (mProcessingRequest) {
+ std::chrono::seconds timeout = std::chrono::seconds(kFlushWaitTimeoutSec);
+ auto st = mRequestDoneCond.wait_for(lk, timeout);
+ if (st == std::cv_status::timeout) {
+ ALOGE("%s: wait for inflight request finish timeout!", __FUNCTION__);
+ }
+ }
+
+ lk.unlock();
+ for (const auto& req : reqs) {
+ parent->processCaptureRequestError(req);
+ }
}
-void ExternalCameraDeviceSession::OutputThread::waitForNextRequest(HalRequest* out) {
+void ExternalCameraDeviceSession::OutputThread::waitForNextRequest(
+ std::shared_ptr<HalRequest>* out) {
if (out == nullptr) {
ALOGE("%s: out is null", __FUNCTION__);
return;
}
- std::unique_lock<std::mutex> lk(mLock);
+ std::unique_lock<std::mutex> lk(mRequestListLock);
+ int waitTimes = 0;
while (mRequestList.empty()) {
- std::chrono::seconds timeout = std::chrono::seconds(kReqWaitTimeoutSec);
+ if (exitPending()) {
+ return;
+ }
+ std::chrono::milliseconds timeout = std::chrono::milliseconds(kReqWaitTimeoutMs);
auto st = mRequestCond.wait_for(lk, timeout);
if (st == std::cv_status::timeout) {
- // no new request, return
- return;
+ waitTimes++;
+ if (waitTimes == kReqWaitTimesMax) {
+ // no new request, return
+ return;
+ }
}
}
*out = mRequestList.front();
mRequestList.pop_front();
+ mProcessingRequest = true;
+ mProcessingFrameNumer = (*out)->frameNumber;
+}
+
+void ExternalCameraDeviceSession::OutputThread::signalRequestDone() {
+ std::unique_lock<std::mutex> lk(mRequestListLock);
+ mProcessingRequest = false;
+ mProcessingFrameNumer = 0;
+ lk.unlock();
+ mRequestDoneCond.notify_one();
+}
+
+void ExternalCameraDeviceSession::OutputThread::dump(int fd) {
+ std::lock_guard<std::mutex> lk(mRequestListLock);
+ if (mProcessingRequest) {
+ dprintf(fd, "OutputThread processing frame %d\n", mProcessingFrameNumer);
+ } else {
+ dprintf(fd, "OutputThread not processing any frames\n");
+ }
+ dprintf(fd, "OutputThread request list contains frame: ");
+ for (const auto& req : mRequestList) {
+ dprintf(fd, "%d, ", req->frameNumber);
+ }
+ dprintf(fd, "\n");
}
void ExternalCameraDeviceSession::cleanupBuffersLocked(int id) {
@@ -1893,7 +2020,8 @@
float fps = 1000.f;
const float kDefaultFps = 30.f;
// Try to pick the slowest fps that is at least 30
- for (const auto& f : v4l2Fmt.frameRates) {
+ for (const auto& fr : v4l2Fmt.frameRates) {
+ double f = fr.getDouble();
if (maxFps < f) {
maxFps = f;
}
@@ -1997,15 +2125,25 @@
return OK;
}
-sp<V4L2Frame> ExternalCameraDeviceSession::dequeueV4l2FrameLocked() {
+sp<V4L2Frame> ExternalCameraDeviceSession::dequeueV4l2FrameLocked(/*out*/nsecs_t* shutterTs) {
sp<V4L2Frame> ret = nullptr;
+ if (shutterTs == nullptr) {
+ ALOGE("%s: shutterTs must not be null!", __FUNCTION__);
+ return ret;
+ }
+
{
std::unique_lock<std::mutex> lk(mV4l2BufferLock);
if (mNumDequeuedV4l2Buffers == mV4L2BufferCount) {
std::chrono::seconds timeout = std::chrono::seconds(kBufferWaitTimeoutSec);
mLock.unlock();
auto st = mV4L2BufferReturned.wait_for(lk, timeout);
+ // Here we introduce a case where mV4l2BufferLock is acquired before mLock, while
+ // the normal lock acquisition order is reversed, but this is fine because in most of
+ // cases we are protected by mInterfaceLock. The only thread that can compete these
+ // locks are the OutputThread, where we do need to make sure we don't acquire mLock then
+ // mV4l2BufferLock
mLock.lock();
if (st == std::cv_status::timeout) {
ALOGE("%s: wait for V4L2 buffer return timeout!", __FUNCTION__);
@@ -2032,6 +2170,15 @@
// TODO: try to dequeue again
}
+ if (buffer.flags & V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC) {
+ // Ideally we should also check for V4L2_BUF_FLAG_TSTAMP_SRC_SOE, but
+ // even V4L2_BUF_FLAG_TSTAMP_SRC_EOF is better than capture a timestamp now
+ *shutterTs = static_cast<nsecs_t>(buffer.timestamp.tv_sec)*1000000000LL +
+ buffer.timestamp.tv_usec * 1000LL;
+ } else {
+ *shutterTs = systemTime(SYSTEM_TIME_MONOTONIC);
+ }
+
{
std::lock_guard<std::mutex> lk(mV4l2BufferLock);
mNumDequeuedV4l2Buffers++;
@@ -2042,22 +2189,27 @@
}
void ExternalCameraDeviceSession::enqueueV4l2Frame(const sp<V4L2Frame>& frame) {
- Mutex::Autolock _l(mLock);
- frame->unmap();
- v4l2_buffer buffer{};
- buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buffer.memory = V4L2_MEMORY_MMAP;
- buffer.index = frame->mBufferIndex;
- if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QBUF, &buffer)) < 0) {
- ALOGE("%s: QBUF index %d fails: %s", __FUNCTION__, frame->mBufferIndex, strerror(errno));
- return;
+ {
+ // Release mLock before acquiring mV4l2BufferLock to avoid potential
+ // deadlock
+ Mutex::Autolock _l(mLock);
+ frame->unmap();
+ v4l2_buffer buffer{};
+ buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buffer.memory = V4L2_MEMORY_MMAP;
+ buffer.index = frame->mBufferIndex;
+ if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QBUF, &buffer)) < 0) {
+ ALOGE("%s: QBUF index %d fails: %s", __FUNCTION__,
+ frame->mBufferIndex, strerror(errno));
+ return;
+ }
}
{
std::lock_guard<std::mutex> lk(mV4l2BufferLock);
mNumDequeuedV4l2Buffers--;
- mV4L2BufferReturned.notify_one();
}
+ mV4L2BufferReturned.notify_one();
}
Status ExternalCameraDeviceSession::configureStreams(
@@ -2335,8 +2487,8 @@
bool support30Fps = false;
int32_t maxFps = std::numeric_limits<int32_t>::min();
for (const auto& supportedFormat : mSupportedFormats) {
- for (const auto& frameRate : supportedFormat.frameRates) {
- int32_t framerateInt = static_cast<int32_t>(frameRate);
+ for (const auto& fr : supportedFormat.frameRates) {
+ int32_t framerateInt = static_cast<int32_t>(fr.getDouble());
if (maxFps < framerateInt) {
maxFps = framerateInt;
}
diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp
index 80f296c..d28a4dd 100644
--- a/camera/device/3.4/default/ExternalCameraUtils.cpp
+++ b/camera/device/3.4/default/ExternalCameraUtils.cpp
@@ -147,6 +147,10 @@
return (std::abs(ar1 - ar2) < kAspectRatioMatchThres);
}
+double SupportedV4L2Format::FrameRate::getDouble() const {
+ return durationDenominator / static_cast<double>(durationNumerator);
+}
+
} // namespace implementation
} // namespace V3_4
} // namespace device
@@ -247,7 +251,7 @@
limit.size = {
row->UnsignedAttribute("width", /*Default*/0),
row->UnsignedAttribute("height", /*Default*/0)};
- limit.fpsUpperBound = row->FloatAttribute("fpsBound", /*Default*/1000.0);
+ limit.fpsUpperBound = row->DoubleAttribute("fpsBound", /*Default*/1000.0);
if (limit.size.width <= prevLimit.size.width ||
limit.size.height <= prevLimit.size.height ||
limit.fpsUpperBound >= prevLimit.fpsUpperBound) {
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
index a7eb121..9c0ad7f 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
@@ -91,6 +91,7 @@
const std::vector<SupportedV4L2Format>& sortedFormats,
const CroppingType& croppingType,
const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId,
unique_fd v4l2Fd);
virtual ~ExternalCameraDeviceSession();
// Call by CameraDevice to dump active device states
@@ -180,7 +181,7 @@
int v4l2StreamOffLocked();
// TODO: change to unique_ptr for better tracking
- sp<V4L2Frame> dequeueV4l2FrameLocked(); // Called with mLock hold
+ sp<V4L2Frame> dequeueV4l2FrameLocked(/*out*/nsecs_t* shutterTs); // Called with mLock hold
void enqueueV4l2Frame(const sp<V4L2Frame>&);
// Check if input Stream is one of supported stream setting on this device
@@ -198,8 +199,8 @@
Status processOneCaptureRequest(const CaptureRequest& request);
- Status processCaptureResult(HalRequest&);
- Status processCaptureRequestError(HalRequest&);
+ Status processCaptureResult(std::shared_ptr<HalRequest>&);
+ Status processCaptureRequestError(const std::shared_ptr<HalRequest>&);
void notifyShutter(uint32_t frameNumber, nsecs_t shutterTs);
void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec);
void invokeProcessCaptureResultCallback(
@@ -219,8 +220,9 @@
Status allocateIntermediateBuffers(
const Size& v4lSize, const Size& thumbSize,
const hidl_vec<Stream>& streams);
- Status submitRequest(const HalRequest&);
+ Status submitRequest(const std::shared_ptr<HalRequest>&);
void flush();
+ void dump(int fd);
virtual bool threadLoop() override;
private:
@@ -232,9 +234,13 @@
static int getCropRect(
CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out);
- static const int kReqWaitTimeoutSec = 3;
+ static const int kFlushWaitTimeoutSec = 3; // 3 sec
+ static const int kReqWaitTimeoutMs = 33; // 33ms
+ static const int kReqWaitTimesMax = 90; // 33ms * 90 ~= 3 sec
- void waitForNextRequest(HalRequest* out);
+ void waitForNextRequest(std::shared_ptr<HalRequest>* out);
+ void signalRequestDone();
+
int cropAndScaleLocked(
sp<AllocatedFrame>& in, const Size& outSize,
YCbCrLayout* out);
@@ -252,17 +258,24 @@
void *out, size_t maxOutSize,
size_t &actualCodeSize);
- int createJpegLocked(HalStreamBuffer &halBuf, HalRequest &req);
+ int createJpegLocked(HalStreamBuffer &halBuf, const std::shared_ptr<HalRequest>& req);
- mutable std::mutex mLock;
- std::condition_variable mRequestCond;
- wp<ExternalCameraDeviceSession> mParent;
- CroppingType mCroppingType;
- std::list<HalRequest> mRequestList;
+ const wp<ExternalCameraDeviceSession> mParent;
+ const CroppingType mCroppingType;
+
+ mutable std::mutex mRequestListLock; // Protect acccess to mRequestList,
+ // mProcessingRequest and mProcessingFrameNumer
+ std::condition_variable mRequestCond; // signaled when a new request is submitted
+ std::condition_variable mRequestDoneCond; // signaled when a request is done processing
+ std::list<std::shared_ptr<HalRequest>> mRequestList;
+ bool mProcessingRequest = false;
+ uint32_t mProcessingFrameNumer = 0;
+
// V4L2 frameIn
// (MJPG decode)-> mYu12Frame
// (Scale)-> mScaledYu12Frames
// (Format convert) -> output gralloc frames
+ mutable std::mutex mBufferLock; // Protect access to intermediate buffers
sp<AllocatedFrame> mYu12Frame;
sp<AllocatedFrame> mYu12ThumbFrame;
std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
@@ -280,7 +293,9 @@
const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
const std::vector<SupportedV4L2Format> mSupportedFormats;
const CroppingType mCroppingType;
+ const std::string& mCameraId;
unique_fd mV4l2Fd;
+
// device is closed either
// - closed by user
// - init failed
@@ -299,6 +314,7 @@
std::condition_variable mV4L2BufferReturned;
size_t mNumDequeuedV4l2Buffers = 0;
+ // Not protected by mLock (but might be used when mLock is locked)
sp<OutputThread> mOutputThread;
// Stream ID -> Camera3Stream cache
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
index e56160a..37e7cfb 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
@@ -73,7 +73,7 @@
struct FpsLimitation {
Size size;
- float fpsUpperBound;
+ double fpsUpperBound;
};
std::vector<FpsLimitation> fpsLimits;
@@ -93,7 +93,12 @@
uint32_t height;
uint32_t fourcc;
// All supported frame rate for this w/h/fourcc combination
- std::vector<float> frameRates;
+ struct FrameRate {
+ uint32_t durationNumerator; // frame duration numerator. Ex: 1
+ uint32_t durationDenominator; // frame duration denominator. Ex: 30
+ double getDouble() const; // FrameRate in double. Ex: 30.0
+ };
+ std::vector<FrameRate> frameRates;
};
// A class provide access to a dequeued V4L2 frame buffer (mostly in MJPG format)
diff --git a/camera/device/3.4/types.hal b/camera/device/3.4/types.hal
index 5681a5c..bf2b3fc 100644
--- a/camera/device/3.4/types.hal
+++ b/camera/device/3.4/types.hal
@@ -177,9 +177,14 @@
/**
* If fmqSettingsSize is zero, the settings buffer contains the capture and
- * processing parameters for the physical device with id 'phyCamId'.
- * In case the individual settings are empty or missing, Hal should fail the
- * request and return Status::ILLEGAL_ARGUMENT.
+ * processing parameters for the physical device with id 'physicalCameraId'.
+ * As a special case, an empty settings buffer indicates that the
+ * settings are identical to the most-recently submitted capture request.
+ * An empty buffer cannot be used as the first submitted request after
+ * a configureStreams() call.
+ *
+ * This field must be used if fmqSettingsSize is zero. It must not be used
+ * if fmqSettingsSize is non-zero.
*/
CameraMetadata settings;
};
diff --git a/camera/provider/2.4/ICameraProvider.hal b/camera/provider/2.4/ICameraProvider.hal
index 3015b7d..abb6366 100644
--- a/camera/provider/2.4/ICameraProvider.hal
+++ b/camera/provider/2.4/ICameraProvider.hal
@@ -35,22 +35,23 @@
* where
* - <major>/<minor> is the provider HAL HIDL version,
* - <type> is the type of devices this provider knows about, such as
- * "internal", "legacy", "usb", or "remote"
+ * "internal", "legacy", "external", or "remote"
* - <instance> is a non-negative integer starting from 0 to disambiguate
* between multiple HALs of the same type.
*
* The "legacy" type is only used for passthrough legacy HAL mode, and must
* not be used by a standalone binderized HAL.
*
- * The device instance names enumerated by the provider must be of the form
+ * The device instance names enumerated by the provider in getCameraIdList() or
+ * ICameraProviderCallback::cameraDeviceStatusChange() must be of the form
* "device@<major>.<minor>/<type>/<id>" where
* <major>/<minor> is the HIDL version of the interface. <id> is either a small
* incrementing integer for "internal" device types, with 0 being the main
* back-facing camera and 1 being the main front-facing camera, if they exist.
- * Or, for external devices such as type "usb", a unique serial number that can
- * be used to identify the device reliably when it is disconnected and
- * reconnected. Multiple providers may not enumerate the same device ID.
+ * Or, for external devices, a unique serial number (if possible) that can be
+ * used to identify the device reliably when it is disconnected and reconnected.
*
+ * Multiple providers must not enumerate the same device ID.
*/
interface ICameraProvider {
@@ -97,7 +98,7 @@
getVendorTags() generates (Status status, vec<VendorTagSection> sections);
/**
- * getCameraDeviceList:
+ * getCameraIdList:
*
* Returns the list of internal camera device interfaces known to this
* camera provider. These devices can then be accessed via the hardware
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 1405ea9..e78dbe8 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -116,6 +116,7 @@
const int64_t kTorchTimeoutSec = 1;
const int64_t kEmptyFlushTimeoutMSec = 200;
const char kDumpOutput[] = "/dev/null";
+const uint32_t kBurstFrameCount = 10;
struct AvailableStream {
int32_t width;
@@ -655,6 +656,13 @@
static Status isLogicalMultiCamera(camera_metadata_t *staticMeta);
static Status getPhysicalCameraIds(camera_metadata_t *staticMeta,
std::unordered_set<std::string> *physicalIds/*out*/);
+ static Status getSupportedKeys(camera_metadata_t *staticMeta,
+ uint32_t tagId, std::unordered_set<int32_t> *requestIDs/*out*/);
+ static void constructFilteredSettings(const sp<ICameraDeviceSession>& session,
+ const std::unordered_set<int32_t>& availableKeys, RequestTemplate reqTemplate,
+ android::hardware::camera::common::V1_0::helper::CameraMetadata* defaultSettings/*out*/,
+ android::hardware::camera::common::V1_0::helper::CameraMetadata* filteredSettings
+ /*out*/);
static Status pickConstrainedModeSize(camera_metadata_t *staticMeta,
AvailableStream &hfrStream);
static Status isZSLModeAvailable(camera_metadata_t *staticMeta);
@@ -712,6 +720,20 @@
// return from HAL but framework.
::android::Vector<StreamBuffer> resultOutputBuffers;
+ InFlightRequest() :
+ shutterTimestamp(0),
+ errorCodeValid(false),
+ errorCode(ErrorCode::ERROR_BUFFER),
+ usePartialResult(false),
+ numPartialResults(0),
+ resultQueue(nullptr),
+ haveResultMetadata(false),
+ numBuffersLeft(0),
+ frameNumber(0),
+ partialResultCount(0),
+ errorStreamId(-1),
+ hasInputBuffer(false) {}
+
InFlightRequest(ssize_t numBuffers, bool hasInput,
bool partialResults, uint32_t partialCount,
std::shared_ptr<ResultMetadataQueue> queue = nullptr) :
@@ -2748,42 +2770,23 @@
castSession(session, deviceVersion, &session3_3, &session3_4);
ASSERT_NE(session3_4, nullptr);
- const android::hardware::camera::common::V1_0::helper::CameraMetadata staticMeta(
- staticMetaBuffer);
- camera_metadata_ro_entry availableSessionKeys = staticMeta.find(
- ANDROID_REQUEST_AVAILABLE_SESSION_KEYS);
- if (availableSessionKeys.count == 0) {
+ std::unordered_set<int32_t> availableSessionKeys;
+ auto rc = getSupportedKeys(staticMetaBuffer, ANDROID_REQUEST_AVAILABLE_SESSION_KEYS,
+ &availableSessionKeys);
+ ASSERT_TRUE(Status::OK == rc);
+ if (availableSessionKeys.empty()) {
+ free_camera_metadata(staticMetaBuffer);
ret = session->close();
ASSERT_TRUE(ret.isOk());
continue;
}
android::hardware::camera::common::V1_0::helper::CameraMetadata previewRequestSettings;
- ret = session->constructDefaultRequestSettings(RequestTemplate::PREVIEW,
- [&previewRequestSettings] (auto status, const auto& req) mutable {
- ASSERT_EQ(Status::OK, status);
-
- const camera_metadata_t *metadata = reinterpret_cast<const camera_metadata_t*> (
- req.data());
- size_t expectedSize = req.size();
- int result = validate_camera_metadata_structure(metadata, &expectedSize);
- ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
-
- size_t entryCount = get_camera_metadata_entry_count(metadata);
- ASSERT_GT(entryCount, 0u);
- previewRequestSettings = metadata;
- });
- ASSERT_TRUE(ret.isOk());
- const android::hardware::camera::common::V1_0::helper::CameraMetadata &constSettings =
- previewRequestSettings;
android::hardware::camera::common::V1_0::helper::CameraMetadata sessionParams;
- for (size_t i = 0; i < availableSessionKeys.count; i++) {
- camera_metadata_ro_entry entry = constSettings.find(availableSessionKeys.data.i32[i]);
- if (entry.count > 0) {
- sessionParams.update(entry);
- }
- }
+ constructFilteredSettings(session, availableSessionKeys, RequestTemplate::PREVIEW,
+ &previewRequestSettings, &sessionParams);
if (sessionParams.isEmpty()) {
+ free_camera_metadata(staticMetaBuffer);
ret = session->close();
ASSERT_TRUE(ret.isOk());
continue;
@@ -2817,7 +2820,7 @@
});
ASSERT_TRUE(ret.isOk());
- sessionParams.unlock(sessionParamsBuffer);
+ free_camera_metadata(staticMetaBuffer);
ret = session->close();
ASSERT_TRUE(ret.isOk());
}
@@ -3350,6 +3353,8 @@
if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_4) {
continue;
}
+ std::string version, deviceId;
+ ASSERT_TRUE(::matchDeviceName(name, mProviderType, &version, &deviceId));
camera_metadata_t* staticMeta;
Return<void> ret;
sp<ICameraDeviceSession> session;
@@ -3357,6 +3362,7 @@
Status rc = isLogicalMultiCamera(staticMeta);
if (Status::METHOD_NOT_SUPPORTED == rc) {
+ free_camera_metadata(staticMeta);
ret = session->close();
ASSERT_TRUE(ret.isOk());
continue;
@@ -3366,13 +3372,45 @@
ASSERT_TRUE(Status::OK == rc);
ASSERT_TRUE(physicalIds.size() > 1);
+ std::unordered_set<int32_t> physicalRequestKeyIDs;
+ rc = getSupportedKeys(staticMeta,
+ ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS, &physicalRequestKeyIDs);
+ ASSERT_TRUE(Status::OK == rc);
+ if (physicalRequestKeyIDs.empty()) {
+ free_camera_metadata(staticMeta);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ // The logical camera doesn't support any individual physical requests.
+ continue;
+ }
+
+ android::hardware::camera::common::V1_0::helper::CameraMetadata defaultPreviewSettings;
+ android::hardware::camera::common::V1_0::helper::CameraMetadata filteredSettings;
+ constructFilteredSettings(session, physicalRequestKeyIDs, RequestTemplate::PREVIEW,
+ &defaultPreviewSettings, &filteredSettings);
+ if (filteredSettings.isEmpty()) {
+ // No physical device settings in default request.
+ free_camera_metadata(staticMeta);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+
+ const camera_metadata_t *settingsBuffer = defaultPreviewSettings.getAndLock();
+ settings.setToExternal(
+ reinterpret_cast<uint8_t *> (const_cast<camera_metadata_t *> (settingsBuffer)),
+ get_camera_metadata_size(settingsBuffer));
+
free_camera_metadata(staticMeta);
ret = session->close();
ASSERT_TRUE(ret.isOk());
- // Leave only 2 physical devices in the id set.
- auto it = physicalIds.begin(); it++; it++;
- physicalIds.erase(it, physicalIds.end());
+ auto it = physicalIds.begin();
+ string physicalDeviceId = *it;
+ // Leave only the first physical device in the id set and insert the logical device.
+ physicalIds.erase(++it, physicalIds.end());
+ physicalIds.emplace(deviceId);
+ ASSERT_EQ(physicalIds.size(), 2u);
V3_4::HalStreamConfiguration halStreamConfig;
bool supportsPartialResults = false;
@@ -3400,38 +3438,34 @@
});
ASSERT_TRUE(resultQueueRet.isOk());
- InFlightRequest inflightReq = {static_cast<ssize_t> (physicalIds.size()), false,
+ InFlightRequest inflightReq = {static_cast<ssize_t> (halStreamConfig.streams.size()), false,
supportsPartialResults, partialResultCount, resultQueue};
- RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
- ret = session3_4->constructDefaultRequestSettings(reqTemplate,
- [&](auto status, const auto& req) {
- ASSERT_EQ(Status::OK, status);
- settings = req;
- });
- ASSERT_TRUE(ret.isOk());
- ASSERT_TRUE(settings.size() > 0);
-
std::vector<sp<GraphicBuffer>> graphicBuffers;
- graphicBuffers.reserve(physicalIds.size());
+ graphicBuffers.reserve(halStreamConfig.streams.size());
::android::hardware::hidl_vec<StreamBuffer> outputBuffers;
- outputBuffers.resize(physicalIds.size());
- hidl_vec<V3_4::PhysicalCameraSetting> camSettings;
- camSettings.resize(physicalIds.size());
+ outputBuffers.resize(halStreamConfig.streams.size());
size_t k = 0;
- for (const auto physicalIdIt : physicalIds) {
+ for (const auto& halStream : halStreamConfig.streams) {
sp<GraphicBuffer> gb = new GraphicBuffer(previewStream.width, previewStream.height,
- static_cast<int32_t>(halStreamConfig.streams[k].v3_3.v3_2.overrideFormat), 1,
+ static_cast<int32_t>(halStream.v3_3.v3_2.overrideFormat), 1,
android_convertGralloc1To0Usage(
- halStreamConfig.streams[k].v3_3.v3_2.producerUsage,
- halStreamConfig.streams[k].v3_3.v3_2.consumerUsage));
+ halStream.v3_3.v3_2.producerUsage, halStream.v3_3.v3_2.consumerUsage));
ASSERT_NE(nullptr, gb.get());
- outputBuffers[k] = {halStreamConfig.streams[k].v3_3.v3_2.id, bufferId,
- hidl_handle(gb->getNativeBuffer()->handle), BufferStatus::OK, nullptr, nullptr};
graphicBuffers.push_back(gb);
- camSettings[k] = {0, hidl_string(physicalIdIt), settings};
+ outputBuffers[k] = {halStream.v3_3.v3_2.id, bufferId,
+ hidl_handle(gb->getNativeBuffer()->handle), BufferStatus::OK, nullptr, nullptr};
+ bufferId++;
k++;
}
+ hidl_vec<V3_4::PhysicalCameraSetting> camSettings(1);
+ const camera_metadata_t *filteredSettingsBuffer = filteredSettings.getAndLock();
+ camSettings[0].settings.setToExternal(
+ reinterpret_cast<uint8_t *> (const_cast<camera_metadata_t *> (
+ filteredSettingsBuffer)),
+ get_camera_metadata_size(filteredSettingsBuffer));
+ camSettings[0].fmqSettingsSize = 0;
+ camSettings[0].physicalCameraId = physicalDeviceId;
StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
V3_4::CaptureRequest request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
@@ -3468,24 +3502,49 @@
ASSERT_FALSE(inflightReq.errorCodeValid);
ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
+
+ request.v3_2.frameNumber++;
+ // Empty settings should be supported after the first call
+ // for repeating requests.
+ request.v3_2.settings.setToExternal(nullptr, 0, true);
+ request.physicalCameraSettings[0].settings.setToExternal(nullptr, 0, true);
+ // The buffer has been registered to HAL by bufferId, so per
+ // API contract we should send a null handle for this buffer
+ request.v3_2.outputBuffers[0].buffer = nullptr;
+ mInflightMap.clear();
+ inflightReq = {static_cast<ssize_t> (physicalIds.size()), false,
+ supportsPartialResults, partialResultCount, resultQueue};
+ mInflightMap.add(request.v3_2.frameNumber, &inflightReq);
}
- // Empty physical camera settings should fail process requests
- camSettings[1].settings = emptySettings;
- frameNumber++;
- request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
- emptyInputBuffer, outputBuffers}, camSettings};
returnStatus = session3_4->processCaptureRequest_3_4(
{request}, cachesToRemove, [&stat, &numRequestProcessed](auto s, uint32_t n) {
stat = s;
numRequestProcessed = n;
});
ASSERT_TRUE(returnStatus.isOk());
- ASSERT_EQ(Status::ILLEGAL_ARGUMENT, stat);
+ ASSERT_EQ(Status::OK, stat);
+ ASSERT_EQ(numRequestProcessed, 1u);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ while (!inflightReq.errorCodeValid &&
+ ((0 < inflightReq.numBuffersLeft) ||
+ (!inflightReq.haveResultMetadata))) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kStreamBufferTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mResultCondition.wait_until(l, timeout));
+ }
+
+ ASSERT_FALSE(inflightReq.errorCodeValid);
+ ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
+ }
// Invalid physical camera id should fail process requests
- camSettings[1].physicalCameraId = invalidPhysicalId;
- camSettings[1].settings = settings;
+ frameNumber++;
+ camSettings[0].physicalCameraId = invalidPhysicalId;
+ camSettings[0].settings = settings;
request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
emptyInputBuffer, outputBuffers}, camSettings};
returnStatus = session3_4->processCaptureRequest_3_4(
@@ -3496,11 +3555,158 @@
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::ILLEGAL_ARGUMENT, stat);
+ defaultPreviewSettings.unlock(settingsBuffer);
+ filteredSettings.unlock(filteredSettingsBuffer);
ret = session3_4->close();
ASSERT_TRUE(ret.isOk());
}
}
+// Generate and verify a burst containing alternating sensor sensitivity values
+TEST_F(CameraHidlTest, processCaptureRequestBurstISO) {
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+ AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+ static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+ uint64_t bufferId = 1;
+ uint32_t frameNumber = 1;
+ ::android::hardware::hidl_vec<uint8_t> settings;
+
+ for (const auto& name : cameraDeviceNames) {
+ int deviceVersion = getCameraDeviceVersion(name, mProviderType);
+ if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+ continue;
+ } else if (deviceVersion <= 0) {
+ ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+ ADD_FAILURE();
+ return;
+ }
+ camera_metadata_t* staticMetaBuffer;
+ Return<void> ret;
+ sp<ICameraDeviceSession> session;
+ openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMetaBuffer /*out*/);
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata staticMeta(
+ staticMetaBuffer);
+
+ camera_metadata_entry_t hwLevel = staticMeta.find(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL);
+ ASSERT_TRUE(0 < hwLevel.count);
+ if (ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED == hwLevel.data.u8[0]) {
+ //Limited devices can skip this test
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+
+ camera_metadata_entry_t isoRange = staticMeta.find(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE);
+ ASSERT_EQ(isoRange.count, 2u);
+
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+
+ bool supportsPartialResults = false;
+ uint32_t partialResultCount = 0;
+ V3_2::Stream previewStream;
+ HalStreamConfiguration halStreamConfig;
+ configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold,
+ &session /*out*/, &previewStream /*out*/, &halStreamConfig /*out*/,
+ &supportsPartialResults /*out*/, &partialResultCount /*out*/);
+ std::shared_ptr<ResultMetadataQueue> resultQueue;
+
+ auto resultQueueRet = session->getCaptureResultMetadataQueue(
+ [&resultQueue](const auto& descriptor) {
+ resultQueue = std::make_shared<ResultMetadataQueue>(descriptor);
+ if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
+ ALOGE("%s: HAL returns empty result metadata fmq,"
+ " not use it", __func__);
+ resultQueue = nullptr;
+ // Don't use the queue onwards.
+ }
+ });
+ ASSERT_TRUE(resultQueueRet.isOk());
+ ASSERT_NE(nullptr, resultQueue);
+
+ ret = session->constructDefaultRequestSettings(RequestTemplate::PREVIEW,
+ [&](auto status, const auto& req) {
+ ASSERT_EQ(Status::OK, status);
+ settings = req; });
+ ASSERT_TRUE(ret.isOk());
+
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata requestMeta;
+ StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
+ sp<GraphicBuffer> buffers[kBurstFrameCount];
+ StreamBuffer outputBuffers[kBurstFrameCount];
+ CaptureRequest requests[kBurstFrameCount];
+ InFlightRequest inflightReqs[kBurstFrameCount];
+ int32_t isoValues[kBurstFrameCount];
+ hidl_vec<uint8_t> requestSettings[kBurstFrameCount];
+ for (uint32_t i = 0; i < kBurstFrameCount; i++) {
+ std::unique_lock<std::mutex> l(mLock);
+
+ isoValues[i] = ((i % 2) == 0) ? isoRange.data.i32[0] : isoRange.data.i32[1];
+ buffers[i] = new GraphicBuffer( previewStream.width, previewStream.height,
+ static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1,
+ android_convertGralloc1To0Usage( halStreamConfig.streams[0].producerUsage,
+ halStreamConfig.streams[0].consumerUsage));
+ ASSERT_NE(nullptr, buffers[i].get());
+
+ outputBuffers[i] = {halStreamConfig.streams[0].id, bufferId + i,
+ hidl_handle( buffers[i]->getNativeBuffer()->handle), BufferStatus::OK, nullptr,
+ nullptr};
+ requestMeta.append(reinterpret_cast<camera_metadata_t *> (settings.data()));
+
+ // Disable all 3A routines
+ uint8_t mode = static_cast<uint8_t>(ANDROID_CONTROL_MODE_OFF);
+ ASSERT_EQ(::android::OK, requestMeta.update(ANDROID_CONTROL_MODE, &mode, 1));
+ ASSERT_EQ(::android::OK, requestMeta.update(ANDROID_SENSOR_SENSITIVITY, &isoValues[i],
+ 1));
+ camera_metadata_t *metaBuffer = requestMeta.release();
+ requestSettings[i].setToExternal(reinterpret_cast<uint8_t *> (metaBuffer),
+ get_camera_metadata_size(metaBuffer), true);
+
+ requests[i] = {frameNumber + i, 0 /* fmqSettingsSize */, requestSettings[i],
+ emptyInputBuffer, {outputBuffers[i]}};
+
+ inflightReqs[i] = {1, false, supportsPartialResults, partialResultCount, resultQueue};
+ mInflightMap.add(frameNumber + i, &inflightReqs[i]);
+ }
+
+ Status status = Status::INTERNAL_ERROR;
+ uint32_t numRequestProcessed = 0;
+ hidl_vec<BufferCache> cachesToRemove;
+ hidl_vec<CaptureRequest> burstRequest;
+ burstRequest.setToExternal(requests, kBurstFrameCount);
+ Return<void> returnStatus = session->processCaptureRequest(burstRequest, cachesToRemove,
+ [&status, &numRequestProcessed] (auto s, uint32_t n) {
+ status = s;
+ numRequestProcessed = n;
+ });
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_EQ(numRequestProcessed, kBurstFrameCount);
+
+ for (size_t i = 0; i < kBurstFrameCount; i++) {
+ std::unique_lock<std::mutex> l(mLock);
+ while (!inflightReqs[i].errorCodeValid && ((0 < inflightReqs[i].numBuffersLeft) ||
+ (!inflightReqs[i].haveResultMetadata))) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kStreamBufferTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+ }
+
+ ASSERT_FALSE(inflightReqs[i].errorCodeValid);
+ ASSERT_NE(inflightReqs[i].resultOutputBuffers.size(), 0u);
+ ASSERT_EQ(previewStream.id, inflightReqs[i].resultOutputBuffers[0].streamId);
+ ASSERT_FALSE(inflightReqs[i].collectedResult.isEmpty());
+ ASSERT_TRUE(inflightReqs[i].collectedResult.exists(ANDROID_SENSOR_SENSITIVITY));
+ camera_metadata_entry_t isoResult = inflightReqs[i].collectedResult.find(
+ ANDROID_SENSOR_SENSITIVITY);
+ ASSERT_TRUE(isoResult.data.i32[0] == isoValues[i]);
+ }
+
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+}
+
// Test whether an incorrect capture request with missing settings will
// be reported correctly.
TEST_F(CameraHidlTest, processCaptureRequestInvalidSinglePreview) {
@@ -3901,6 +4107,56 @@
return Status::OK;
}
+// Generate a set of suported camera key ids.
+Status CameraHidlTest::getSupportedKeys(camera_metadata_t *staticMeta,
+ uint32_t tagId, std::unordered_set<int32_t> *requestIDs) {
+ if ((nullptr == staticMeta) || (nullptr == requestIDs)) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ camera_metadata_ro_entry entry;
+ int rc = find_camera_metadata_ro_entry(staticMeta, tagId, &entry);
+ if ((0 != rc) || (entry.count == 0)) {
+ return Status::OK;
+ }
+
+ requestIDs->insert(entry.data.i32, entry.data.i32 + entry.count);
+
+ return Status::OK;
+}
+
+void CameraHidlTest::constructFilteredSettings(const sp<ICameraDeviceSession>& session,
+ const std::unordered_set<int32_t>& availableKeys, RequestTemplate reqTemplate,
+ android::hardware::camera::common::V1_0::helper::CameraMetadata* defaultSettings,
+ android::hardware::camera::common::V1_0::helper::CameraMetadata* filteredSettings) {
+ ASSERT_NE(defaultSettings, nullptr);
+ ASSERT_NE(filteredSettings, nullptr);
+
+ auto ret = session->constructDefaultRequestSettings(reqTemplate,
+ [&defaultSettings] (auto status, const auto& req) mutable {
+ ASSERT_EQ(Status::OK, status);
+
+ const camera_metadata_t *metadata = reinterpret_cast<const camera_metadata_t*> (
+ req.data());
+ size_t expectedSize = req.size();
+ int result = validate_camera_metadata_structure(metadata, &expectedSize);
+ ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+
+ size_t entryCount = get_camera_metadata_entry_count(metadata);
+ ASSERT_GT(entryCount, 0u);
+ *defaultSettings = metadata;
+ });
+ ASSERT_TRUE(ret.isOk());
+ const android::hardware::camera::common::V1_0::helper::CameraMetadata &constSettings =
+ *defaultSettings;
+ for (const auto& keyIt : availableKeys) {
+ camera_metadata_ro_entry entry = constSettings.find(keyIt);
+ if (entry.count > 0) {
+ filteredSettings->update(entry);
+ }
+ }
+}
+
// Check if constrained mode is supported by using the static
// camera characteristics.
Status CameraHidlTest::isConstrainedModeAvailable(camera_metadata_t *staticMeta) {
diff --git a/cas/1.0/vts/functional/Android.bp b/cas/1.0/vts/functional/Android.bp
index e1e09e9..0db9bb0 100644
--- a/cas/1.0/vts/functional/Android.bp
+++ b/cas/1.0/vts/functional/Android.bp
@@ -23,6 +23,7 @@
"android.hardware.cas.native@1.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
+ "libhidlallocatorutils",
"libhidlmemory",
],
shared_libs: [
diff --git a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
index 053d37a..14b8bbd 100644
--- a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
+++ b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
@@ -30,6 +30,7 @@
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
#include <utils/Condition.h>
#include <utils/Mutex.h>
@@ -53,6 +54,7 @@
using android::hardware::cas::V1_0::ICas;
using android::hardware::cas::V1_0::ICasListener;
using android::hardware::cas::V1_0::IDescramblerBase;
+using android::hardware::cas::V1_0::Status;
using android::hardware::cas::native::V1_0::IDescrambler;
using android::hardware::cas::native::V1_0::SubSample;
using android::hardware::cas::native::V1_0::SharedBuffer;
@@ -61,13 +63,12 @@
using android::hardware::cas::native::V1_0::ScramblingControl;
using android::hardware::cas::V1_0::IMediaCasService;
using android::hardware::cas::V1_0::HidlCasPluginDescriptor;
-using android::hardware::Void;
+using android::hardware::fromHeap;
using android::hardware::hidl_vec;
using android::hardware::hidl_string;
-using android::hardware::hidl_handle;
-using android::hardware::hidl_memory;
+using android::hardware::HidlMemory;
using android::hardware::Return;
-using android::hardware::cas::V1_0::Status;
+using android::hardware::Void;
using android::IMemory;
using android::IMemoryHeap;
using android::MemoryDealer;
@@ -315,7 +316,7 @@
}
*inMemory = mem;
- // build hidl_memory from memory heap
+ // build HidlMemory from memory heap
ssize_t offset;
size_t size;
sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
@@ -324,18 +325,14 @@
return ::testing::AssertionFailure();
}
- native_handle_t* nativeHandle = native_handle_create(1, 0);
- if (!nativeHandle) {
- ALOGE("failed to create native handle!");
- return ::testing::AssertionFailure();
- }
- nativeHandle->data[0] = heap->getHeapID();
-
uint8_t* ipBuffer = static_cast<uint8_t*>(static_cast<void*>(mem->pointer()));
memcpy(ipBuffer, kInBinaryBuffer, sizeof(kInBinaryBuffer));
+ // hidlMemory is not to be passed out of scope!
+ sp<HidlMemory> hidlMemory = fromHeap(heap);
+
SharedBuffer srcBuffer = {
- .heapBase = hidl_memory("ashmem", hidl_handle(nativeHandle), heap->getSize()),
+ .heapBase = *hidlMemory,
.offset = (uint64_t) offset,
.size = (uint64_t) size
};
@@ -380,7 +377,7 @@
return ::testing::AssertionFailure();
}
- // build hidl_memory from memory heap
+ // build HidlMemory from memory heap
ssize_t offset;
size_t size;
sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
@@ -389,15 +386,11 @@
return ::testing::AssertionFailure();
}
- native_handle_t* nativeHandle = native_handle_create(1, 0);
- if (!nativeHandle) {
- ALOGE("failed to create native handle!");
- return ::testing::AssertionFailure();
- }
- nativeHandle->data[0] = heap->getHeapID();
+ // hidlMemory is not to be passed out of scope!
+ sp<HidlMemory> hidlMemory = fromHeap(heap);
SharedBuffer srcBuffer = {
- .heapBase = hidl_memory("ashmem", hidl_handle(nativeHandle), heap->getSize()),
+ .heapBase = *hidlMemory,
.offset = (uint64_t) offset + params.imemOffset,
.size = (uint64_t) params.imemSize,
};
diff --git a/confirmationui/1.0/vts/OWNERS b/confirmationui/1.0/vts/OWNERS
new file mode 100644
index 0000000..e7aa8b4
--- /dev/null
+++ b/confirmationui/1.0/vts/OWNERS
@@ -0,0 +1,3 @@
+jdanis@google.com
+swillden@google.com
+yim@google.com
diff --git a/confirmationui/1.0/vts/functional/Android.bp b/confirmationui/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..823e035
--- /dev/null
+++ b/confirmationui/1.0/vts/functional/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2018 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.
+//
+
+cc_test {
+ name: "VtsHalConfirmationUIV1_0TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "VtsHalConfirmationUIV1_0TargetTest.cpp",
+ ],
+ static_libs: [
+ "android.hardware.confirmationui@1.0",
+ "android.hardware.keymaster@4.0",
+ "libcrypto",
+ "libcn-cbor",
+ "android.hardware.confirmationui-support-lib",
+ ],
+}
diff --git a/confirmationui/1.0/vts/functional/VtsHalConfirmationUIV1_0TargetTest.cpp b/confirmationui/1.0/vts/functional/VtsHalConfirmationUIV1_0TargetTest.cpp
new file mode 100644
index 0000000..463bb40
--- /dev/null
+++ b/confirmationui/1.0/vts/functional/VtsHalConfirmationUIV1_0TargetTest.cpp
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define LOG_TAG "ConfirmationIOHidlHalTest"
+#include <cutils/log.h>
+
+#include <algorithm>
+#include <iostream>
+#include <memory>
+
+#include <android/hardware/confirmationui/1.0/IConfirmationResultCallback.h>
+#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
+#include <android/hardware/confirmationui/1.0/types.h>
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+
+#include <cn-cbor/cn-cbor.h>
+
+using ::android::sp;
+
+using ::std::string;
+
+namespace android {
+namespace hardware {
+
+namespace confirmationui {
+namespace V1_0 {
+
+namespace test {
+namespace {
+class HMacImplementation {
+ public:
+ static support::NullOr<support::array<uint8_t, 32>> hmac256(
+ const uint8_t key[32], std::initializer_list<support::ByteBufferProxy> buffers) {
+ HMAC_CTX hmacCtx;
+ HMAC_CTX_init(&hmacCtx);
+ if (!HMAC_Init_ex(&hmacCtx, key, 32, EVP_sha256(), nullptr)) {
+ return {};
+ }
+ for (auto& buffer : buffers) {
+ if (!HMAC_Update(&hmacCtx, buffer.data(), buffer.size())) {
+ return {};
+ }
+ }
+ support::array<uint8_t, 32> result;
+ if (!HMAC_Final(&hmacCtx, result.data(), nullptr)) {
+ return {};
+ }
+ return result;
+ }
+};
+
+using HMacer = support::HMac<HMacImplementation>;
+
+constexpr uint8_t testKeyByte = static_cast<uint8_t>(TestKeyBits::BYTE);
+
+template <typename... Data>
+hidl_vec<uint8_t> testHMAC(const Data&... data) {
+ constexpr uint8_t testKey[32] = {testKeyByte, testKeyByte, testKeyByte, testKeyByte,
+ testKeyByte, testKeyByte, testKeyByte, testKeyByte,
+ testKeyByte, testKeyByte, testKeyByte, testKeyByte,
+ testKeyByte, testKeyByte, testKeyByte, testKeyByte};
+ constexpr uint8_t hmac_size_bytes = sizeof testKey;
+
+ auto hmac = HMacer::hmac256(testKey, data...);
+ if (!hmac.isOk()) {
+ EXPECT_TRUE(false) << "Failed to compute test hmac. This is a self-test error.";
+ return {};
+ }
+ hidl_vec<uint8_t> result(hmac_size_bytes);
+ copy(hmac.value().data(), hmac.value().data() + hmac_size_bytes, result.data());
+ return result;
+}
+
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType;
+
+template <typename T>
+auto toBytes(const T& v) -> const uint8_t (&)[sizeof(T)] {
+ return *reinterpret_cast<const uint8_t(*)[sizeof(T)]>(&v);
+}
+
+HardwareAuthToken makeTestToken(const TestModeCommands command, uint64_t timestamp = 0) {
+ HardwareAuthToken auth_token;
+ auth_token.challenge = static_cast<uint64_t>(command);
+ auth_token.userId = 0;
+ auth_token.authenticatorId = 0;
+ auth_token.authenticatorType = HardwareAuthenticatorType::NONE;
+ auth_token.timestamp = timestamp;
+
+ // Canonical form of auth-token v0
+ // version (1 byte)
+ // challenge (8 bytes)
+ // user_id (8 bytes)
+ // authenticator_id (8 bytes)
+ // authenticator_type (4 bytes)
+ // timestamp (8 bytes)
+ // total 37 bytes
+ auth_token.mac = testHMAC("\0",
+ toBytes(auth_token.challenge), //
+ toBytes(auth_token.userId), //
+ toBytes(auth_token.authenticatorId), //
+ toBytes(support::hton(auth_token.authenticatorType)), //
+ toBytes(support::hton(auth_token.timestamp))); //
+
+ return auth_token;
+}
+
+#define DEBUG_CONFRIMATIONUI_UTILS_TEST
+
+#ifdef DEBUG_CONFRIMATIONUI_UTILS_TEST
+std::ostream& hexdump(std::ostream& out, const uint8_t* data, size_t size) {
+ for (size_t i = 0; i < size; ++i) {
+ uint8_t byte = data[i];
+ out << std::hex << std::setw(2) << std::setfill('0') << (unsigned)byte;
+ switch (i & 0xf) {
+ case 0xf:
+ out << "\n";
+ break;
+ case 7:
+ out << " ";
+ break;
+ default:
+ out << " ";
+ break;
+ }
+ }
+ return out;
+}
+#endif
+
+constexpr char hex_value[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9'
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F'
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f'
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+std::string hex2str(std::string a) {
+ std::string b;
+ size_t num = a.size() / 2;
+ b.resize(num);
+ for (size_t i = 0; i < num; i++) {
+ b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]);
+ }
+ return b;
+}
+
+} // namespace
+
+class ConfirmationArgs {
+ public:
+ ResponseCode error_;
+ hidl_vec<uint8_t> formattedMessage_;
+ hidl_vec<uint8_t> confirmationToken_;
+ bool verifyConfirmationToken() {
+ static constexpr char confirmationPrefix[] = "confirmation token";
+ EXPECT_EQ(32U, confirmationToken_.size());
+ return 32U == confirmationToken_.size() &&
+ !memcmp(confirmationToken_.data(),
+ testHMAC(confirmationPrefix, formattedMessage_).data(), 32);
+ }
+};
+
+class ConfirmationTestCallback : public ::testing::VtsHalHidlTargetCallbackBase<ConfirmationArgs>,
+ public IConfirmationResultCallback {
+ public:
+ Return<void> result(ResponseCode error, const hidl_vec<uint8_t>& formattedMessage,
+ const hidl_vec<uint8_t>& confirmationToken) override {
+ ConfirmationArgs args;
+ args.error_ = error;
+ args.formattedMessage_ = formattedMessage;
+ args.confirmationToken_ = confirmationToken;
+ NotifyFromCallback(args);
+ return Void();
+ }
+};
+
+class ConfirmationUIHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static ConfirmationUIHidlEnvironment* Instance() {
+ static ConfirmationUIHidlEnvironment* instance = new ConfirmationUIHidlEnvironment;
+ return instance;
+ }
+
+ void registerTestServices() override { registerTestService<IConfirmationUI>(); }
+
+ private:
+ ConfirmationUIHidlEnvironment(){};
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ConfirmationUIHidlEnvironment);
+};
+
+class ConfirmationUIHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ void TearDown() override { confirmator().abort(); }
+
+ static void SetUpTestCase() {
+ string service_name =
+ ConfirmationUIHidlEnvironment::Instance()->getServiceName<IConfirmationUI>();
+ confirmator_ = IConfirmationUI::getService(service_name);
+ ASSERT_NE(nullptr, confirmator_.get());
+ }
+
+ static void TearDownTestCase() { confirmator_.clear(); }
+
+ static IConfirmationUI& confirmator() { return *confirmator_; }
+
+ private:
+ static sp<IConfirmationUI> confirmator_;
+};
+
+sp<IConfirmationUI> ConfirmationUIHidlTest::confirmator_;
+
+#define ASSERT_HAL_CALL(expected, call) \
+ { \
+ auto result = call; \
+ ASSERT_TRUE(result.isOk()); \
+ ASSERT_EQ(expected, static_cast<decltype(expected)>(result)); \
+ }
+
+struct CnCborDeleter {
+ void operator()(cn_cbor* ptr) { cn_cbor_free(ptr); }
+};
+
+typedef std::unique_ptr<cn_cbor, CnCborDeleter> CnCborPtr;
+
+// Simulates the User taping Ok
+TEST_F(ConfirmationUIHidlTest, UserOkTest) {
+ static constexpr char test_prompt[] = "Me first, gimme gimme!";
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ sp<ConfirmationTestCallback> conf_cb = new ConfirmationTestCallback;
+ hidl_string prompt_text(test_prompt);
+ hidl_vec<uint8_t> extra(test_extra, test_extra + 3);
+ ASSERT_HAL_CALL(ResponseCode::OK,
+ confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}));
+
+ ASSERT_HAL_CALL(ResponseCode::OK, confirmator().deliverSecureInputEvent(
+ makeTestToken(TestModeCommands::OK_EVENT)));
+
+ auto result = conf_cb->WaitForCallback();
+ ASSERT_EQ(ResponseCode::OK, result.args->error_);
+
+ ASSERT_TRUE(result.args->verifyConfirmationToken());
+
+ cn_cbor_errback cn_cbor_error;
+ auto parsed_message =
+ CnCborPtr(cn_cbor_decode(result.args->formattedMessage_.data(),
+ result.args->formattedMessage_.size(), &cn_cbor_error));
+ // is parsable CBOR
+ ASSERT_TRUE(parsed_message.get());
+ // is a map
+ ASSERT_EQ(CN_CBOR_MAP, parsed_message->type);
+
+ // the message must have exactly 2 key value pairs.
+ // cn_cbor holds 2*<no_of_pairs> in the length field
+ ASSERT_EQ(4, parsed_message->length);
+ // map has key "prompt"
+ auto prompt = cn_cbor_mapget_string(parsed_message.get(), "prompt");
+ ASSERT_TRUE(prompt);
+ ASSERT_EQ(CN_CBOR_TEXT, prompt->type);
+ ASSERT_EQ(22, prompt->length);
+ ASSERT_EQ(0, memcmp(test_prompt, prompt->v.str, 22));
+ // map has key "extra"
+ auto extra_out = cn_cbor_mapget_string(parsed_message.get(), "extra");
+ ASSERT_TRUE(extra_out);
+ ASSERT_EQ(CN_CBOR_BYTES, extra_out->type);
+ ASSERT_EQ(3, extra_out->length);
+ ASSERT_EQ(0, memcmp(test_extra, extra_out->v.bytes, 3));
+}
+
+// Initiates a confirmation prompt with a message that is too long
+TEST_F(ConfirmationUIHidlTest, MessageTooLongTest) {
+ static constexpr uint8_t test_extra[static_cast<uint32_t>(MessageSize::MAX)] = {};
+ static constexpr char test_prompt[] = "D\'oh!";
+ sp<ConfirmationTestCallback> conf_cb = new ConfirmationTestCallback;
+ hidl_string prompt_text(test_prompt);
+ hidl_vec<uint8_t> extra(test_extra, test_extra + sizeof(test_extra));
+ ASSERT_HAL_CALL(ResponseCode::UIErrorMessageTooLong,
+ confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}));
+}
+
+// If the message gets very long some HAL implementations might fail even before the message
+// reaches the trusted app implementation. But the HAL must still diagnose the correct error.
+TEST_F(ConfirmationUIHidlTest, MessageWayTooLongTest) {
+ static constexpr uint8_t test_extra[static_cast<uint32_t>(MessageSize::MAX) * 10] = {};
+ static constexpr char test_prompt[] = "D\'oh!";
+ sp<ConfirmationTestCallback> conf_cb = new ConfirmationTestCallback;
+ hidl_string prompt_text(test_prompt);
+ hidl_vec<uint8_t> extra(test_extra, test_extra + sizeof(test_extra));
+ ASSERT_HAL_CALL(ResponseCode::UIErrorMessageTooLong,
+ confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}));
+}
+
+// Simulates the User tapping the Cancel
+TEST_F(ConfirmationUIHidlTest, UserCancelTest) {
+ static constexpr char test_prompt[] = "Me first, gimme gimme!";
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ sp<ConfirmationTestCallback> conf_cb = new ConfirmationTestCallback;
+ hidl_string prompt_text(test_prompt);
+ hidl_vec<uint8_t> extra(test_extra, test_extra + 3);
+ ASSERT_HAL_CALL(ResponseCode::OK,
+ confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}));
+
+ ASSERT_HAL_CALL(ResponseCode::OK, confirmator().deliverSecureInputEvent(
+ makeTestToken(TestModeCommands::CANCEL_EVENT)));
+
+ auto result = conf_cb->WaitForCallback();
+ ASSERT_EQ(ResponseCode::Canceled, result.args->error_);
+
+ ASSERT_EQ(0U, result.args->confirmationToken_.size());
+ ASSERT_EQ(0U, result.args->formattedMessage_.size());
+}
+
+// Simulates the framework candelling an ongoing prompt
+TEST_F(ConfirmationUIHidlTest, AbortTest) {
+ static constexpr char test_prompt[] = "Me first, gimme gimme!";
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ sp<ConfirmationTestCallback> conf_cb = new ConfirmationTestCallback;
+ hidl_string prompt_text(test_prompt);
+ hidl_vec<uint8_t> extra(test_extra, test_extra + 3);
+ ASSERT_HAL_CALL(ResponseCode::OK,
+ confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}));
+
+ confirmator().abort();
+
+ auto result = conf_cb->WaitForCallback();
+ ASSERT_EQ(ResponseCode::Aborted, result.args->error_);
+ ASSERT_EQ(0U, result.args->confirmationToken_.size());
+ ASSERT_EQ(0U, result.args->formattedMessage_.size());
+}
+
+// Passing malformed UTF-8 to the confirmation UI
+// This test passes a string that ends in the middle of a multibyte character
+TEST_F(ConfirmationUIHidlTest, MalformedUTF8Test1) {
+ static constexpr char test_prompt[] = {char(0xc0), 0};
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ sp<ConfirmationTestCallback> conf_cb = new ConfirmationTestCallback;
+ hidl_string prompt_text(test_prompt);
+ hidl_vec<uint8_t> extra(test_extra, test_extra + 3);
+ ASSERT_HAL_CALL(ResponseCode::UIErrorMalformedUTF8Encoding,
+ confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}));
+}
+
+// Passing malformed UTF-8 to the confirmation UI
+// This test passes a string with a 5-byte character.
+TEST_F(ConfirmationUIHidlTest, MalformedUTF8Test2) {
+ static constexpr char test_prompt[] = {char(0xf8), char(0x82), char(0x82),
+ char(0x82), char(0x82), 0};
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ sp<ConfirmationTestCallback> conf_cb = new ConfirmationTestCallback;
+ hidl_string prompt_text(test_prompt);
+ hidl_vec<uint8_t> extra(test_extra, test_extra + 3);
+ ASSERT_HAL_CALL(ResponseCode::UIErrorMalformedUTF8Encoding,
+ confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}));
+}
+
+// Passing malformed UTF-8 to the confirmation UI
+// This test passes a string with a 2-byte character followed by a stray non UTF-8 character.
+TEST_F(ConfirmationUIHidlTest, MalformedUTF8Test3) {
+ static constexpr char test_prompt[] = {char(0xc0), char(0x82), char(0x83), 0};
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ sp<ConfirmationTestCallback> conf_cb = new ConfirmationTestCallback;
+ hidl_string prompt_text(test_prompt);
+ hidl_vec<uint8_t> extra(test_extra, test_extra + 3);
+ ASSERT_HAL_CALL(ResponseCode::UIErrorMalformedUTF8Encoding,
+ confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}));
+}
+
+// Test the implementation of HMAC SHA 256 against a golden blob.
+TEST(ConfirmationUITestSelfTest, HMAC256SelfTest) {
+ const char key_str[32] = "keykeykeykeykeykeykeykeykeykeyk";
+ const uint8_t(&key)[32] = *reinterpret_cast<const uint8_t(*)[32]>(key_str);
+ auto expected = hex2str("2377fbcaa7fb3f6c20cfa1d9ebc60e9922cf58c909e25e300f3cb57f7805c886");
+ auto result = HMacer::hmac256(key, "value1", "value2", "value3");
+
+#ifdef DEBUG_CONFRIMATIONUI_UTILS_TEST
+ hexdump(std::cout, reinterpret_cast<const uint8_t*>(expected.data()), 32) << std::endl;
+ hexdump(std::cout, result.value().data(), 32) << std::endl;
+#endif
+
+ support::ByteBufferProxy expected_bytes(expected);
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(expected, result.value());
+}
+
+} // namespace test
+} // namespace V1_0
+} // namespace confirmationui
+} // namespace hardware
+} // namespace android
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ std::vector<std::string> positional_args;
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
index 5672824..7492152 100644
--- a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
+++ b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "contexthub_hidl_hal_test"
#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android/hardware/contexthub/1.0/IContexthub.h>
#include <android/hardware/contexthub/1.0/IContexthubCallback.h>
@@ -92,12 +93,27 @@
return hubIds;
}
+// Test environment for Contexthub HIDL HAL.
+class ContexthubHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static ContexthubHidlEnvironment* Instance() {
+ static ContexthubHidlEnvironment* instance = new ContexthubHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<IContexthub>(); }
+ private:
+ ContexthubHidlEnvironment() {}
+};
+
// Base test fixture that initializes the HAL and makes the context hub API
// handle available
class ContexthubHidlTestBase : public ::testing::VtsHalHidlTargetTestBase {
public:
virtual void SetUp() override {
- hubApi = ::testing::VtsHalHidlTargetTestBase::getService<IContexthub>();
+ hubApi = ::testing::VtsHalHidlTargetTestBase::getService<IContexthub>(
+ ContexthubHidlEnvironment::Instance()->getServiceName<IContexthub>());
ASSERT_NE(hubApi, nullptr);
// getHubs() must be called at least once for proper initialization of the
@@ -381,7 +397,11 @@
} // anonymous namespace
int main(int argc, char **argv) {
+ ::testing::AddGlobalTestEnvironment(ContexthubHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
+ ContexthubHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI ("Test result = %d", status);
+ return status;
}
diff --git a/current.txt b/current.txt
index a5ab307..05660a8 100644
--- a/current.txt
+++ b/current.txt
@@ -251,8 +251,10 @@
# ABI preserving changes to HALs during Android P
cf72ff5a52bfa4d08e9e1000cf3ab5952a2d280c7f13cdad5ab7905c08050766 android.hardware.camera.metadata@3.2::types
+7b4723305354193b889a24153e1292fec62d5a5127bdfba08a5a27440f092de9 android.hardware.camera.provider@2.4::ICameraProvider
6fa9804a17a8bb7923a56bd10493a5483c20007e4c9026fd04287bee7c945a8c android.hardware.gnss@1.0::IGnssCallback
fb92e2b40f8e9d494e8fd3b4ac18499a3216342e7cff160714c3bbf3660b6e79 android.hardware.gnss@1.0::IGnssConfiguration
251594ea9b27447bfa005ebd806e58fb0ae4aad84a69938129c9800ec0c64eda android.hardware.gnss@1.0::IGnssMeasurementCallback
4e7169919d24fbe5573e5bcd683d0bd7abf553a4e6c34c41f9dfc1e12050db07 android.hardware.gnss@1.0::IGnssNavigationMessageCallback
+0e6e80ddd5c312726e20b003af438325a2d7c305a60a8c8d8e229df2306d50df android.hardware.radio@1.0::types
b280c4704dfcc548a9bf127b59b7c3578f460c50cce70a06b66fe0df8b27cff0 android.hardware.wifi@1.0::types
diff --git a/drm/1.0/vts/functional/drm_hal_vendor_test.cpp b/drm/1.0/vts/functional/drm_hal_vendor_test.cpp
index 47c6950..d03b2af 100644
--- a/drm/1.0/vts/functional/drm_hal_vendor_test.cpp
+++ b/drm/1.0/vts/functional/drm_hal_vendor_test.cpp
@@ -97,6 +97,27 @@
static drm_vts::VendorModules* gVendorModules = nullptr;
+// Test environment for drm
+class DrmHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static DrmHidlEnvironment* Instance() {
+ static DrmHidlEnvironment* instance = new DrmHidlEnvironment;
+ return instance;
+ }
+
+ void registerTestServices() override {
+ registerTestService<ICryptoFactory>();
+ registerTestService<IDrmFactory>();
+ setServiceCombMode(::testing::HalServiceCombMode::NO_COMBINATION);
+ }
+
+ private:
+ DrmHidlEnvironment() {}
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DrmHidlEnvironment);
+};
+
class DrmHalVendorFactoryTest : public testing::TestWithParam<std::string> {
public:
DrmHalVendorFactoryTest()
@@ -1598,6 +1619,10 @@
std::cerr << "WARNING: No vendor modules found in " << kModulePath <<
", all vendor tests will be skipped" << std::endl;
}
+ ::testing::AddGlobalTestEnvironment(DrmHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
+ DrmHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
}
diff --git a/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp b/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
index a8ed0e5..061f2cd 100644
--- a/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
+++ b/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
@@ -106,6 +106,12 @@
virtual void HidlTearDown() override { ALOGI("TearDown DrmHidlEnvironment"); }
+ void registerTestServices() override {
+ registerTestService<ICryptoFactory>();
+ registerTestService<IDrmFactory>();
+ setServiceCombMode(::testing::HalServiceCombMode::NO_COMBINATION);
+ }
+
private:
DrmHidlEnvironment() {}
diff --git a/gnss/1.1/Android.bp b/gnss/1.1/Android.bp
index 417b4f5..4ae4439 100644
--- a/gnss/1.1/Android.bp
+++ b/gnss/1.1/Android.bp
@@ -11,6 +11,7 @@
"IGnssCallback.hal",
"IGnssConfiguration.hal",
"IGnssMeasurement.hal",
+ "IGnssMeasurementCallback.hal",
],
interfaces: [
"android.hardware.gnss@1.0",
diff --git a/gnss/1.1/IGnssMeasurement.hal b/gnss/1.1/IGnssMeasurement.hal
index 75df5a8..cd83ae3 100644
--- a/gnss/1.1/IGnssMeasurement.hal
+++ b/gnss/1.1/IGnssMeasurement.hal
@@ -17,7 +17,7 @@
package android.hardware.gnss@1.1;
import @1.0::IGnssMeasurement;
-import @1.0::IGnssMeasurementCallback;
+import IGnssMeasurementCallback;
/**
* Extended interface for GNSS Measurements support.
diff --git a/gnss/1.1/IGnssMeasurementCallback.hal b/gnss/1.1/IGnssMeasurementCallback.hal
new file mode 100644
index 0000000..5a60a56
--- /dev/null
+++ b/gnss/1.1/IGnssMeasurementCallback.hal
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 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 android.hardware.gnss@1.1;
+
+import @1.0::IGnssMeasurementCallback;
+
+/** The callback interface to report measurements from the HAL. */
+interface IGnssMeasurementCallback extends @1.0::IGnssMeasurementCallback {
+ /**
+ * Flags indicating the Accumulated Delta Range's states.
+ */
+ enum GnssAccumulatedDeltaRangeState
+ : @1.0::IGnssMeasurementCallback.GnssAccumulatedDeltaRangeState {
+ ADR_STATE_HALF_CYCLE_RESOLVED = 1 << 3, // Carrier-phase half-cycle ambiguity resolved
+ };
+
+ /**
+ * Extends a GNSS Measurement, adding the new enum.
+ */
+ struct GnssMeasurement {
+ /**
+ * GNSS measurement information for a single satellite and frequency, as in the 1.0
+ * version of the HAL.
+ *
+ * In this version of the HAL, these fields of the
+ * @1.0::IGnssMeasurementCallback.GnssMeasurement v1_0 struct are deprecated, and
+ * are no longer used by the framework:
+ * carrierCycles
+ * carrierPhase
+ * carrierPhaseUncertainty
+ *
+ * Similar information about carrier phase signal tracking is still reported in these
+ * fields of @1.0::IGnssMeasurementCallback.GnssMeasurement v1_0:
+ * accumulatedDeltaRangeM
+ * accumulatedDeltaRangeUncertaintyM
+ */
+ @1.0::IGnssMeasurementCallback.GnssMeasurement v1_0;
+
+ /**
+ * Provides the state of Accumulated Delta Range values, including additional information
+ * beyond version 1.0 of the HAL. See GnssAccumulatedDeltaRangeState.
+ *
+ * In this (1.1) version of the HAL, this value is used by the framework, not the
+ * value provided by v1_0.accumulatedDeltaRangeState.
+ */
+ bitfield<GnssAccumulatedDeltaRangeState> accumulatedDeltaRangeState;
+ };
+
+ /**
+ * Complete set of GNSS Measurement data, same as 1.0 with additional enum in measurements.
+ */
+ struct GnssData {
+ /** The full set of satellite measurement observations. */
+ vec<GnssMeasurement> measurements;
+
+ /** The GNSS clock time reading. */
+ GnssClock clock;
+ };
+
+ /**
+ * Callback for the hal to pass a GnssData structure back to the client.
+ *
+ * @param data Contains a reading of GNSS measurements.
+ */
+ gnssMeasurementCb(GnssData data);
+};
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
index 264a11d..a0a1c73 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -396,6 +396,10 @@
ASSERT_TRUE(result.isOk());
EXPECT_TRUE(result);
+
+ auto resultVoid = gnss_hal_->deleteAidingData(IGnss::GnssAidingData::DELETE_ALL);
+
+ ASSERT_TRUE(resultVoid.isOk());
}
/*
diff --git a/graphics/composer/2.1/default/Android.bp b/graphics/composer/2.1/default/Android.bp
index b46a1de..2de1e3c 100644
--- a/graphics/composer/2.1/default/Android.bp
+++ b/graphics/composer/2.1/default/Android.bp
@@ -1,34 +1,12 @@
-cc_library_static {
- name: "libhwcomposer-client",
- vendor_available: true,
- defaults: ["hidl_defaults"],
- export_include_dirs: ["."],
- srcs: ["ComposerClient.cpp"],
- shared_libs: [
- "android.hardware.graphics.composer@2.1",
- "android.hardware.graphics.mapper@2.0",
- "libbase",
- "libcutils",
- "libfmq",
- "libhardware",
- "libhidlbase",
- "libhidltransport",
- "liblog",
- "libsync",
- "libutils",
- ],
- header_libs: [
- "android.hardware.graphics.composer@2.1-command-buffer",
- ],
-}
-
cc_library_shared {
name: "android.hardware.graphics.composer@2.1-impl",
defaults: ["hidl_defaults"],
- proprietary: true,
+ vendor: true,
relative_install_path: "hw",
- srcs: ["Hwc.cpp"],
- static_libs: ["libhwcomposer-client"],
+ srcs: ["passthrough.cpp"],
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-passthrough",
+ ],
shared_libs: [
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0",
@@ -44,26 +22,21 @@
"libhwc2on1adapter",
"libhwc2onfbadapter",
],
- header_libs: [
- "android.hardware.graphics.composer@2.1-command-buffer",
+ cflags: [
+ "-DLOG_TAG=\"ComposerHal\""
],
}
cc_binary {
name: "android.hardware.graphics.composer@2.1-service",
defaults: ["hidl_defaults"],
- proprietary: true,
+ vendor: true,
relative_install_path: "hw",
srcs: ["service.cpp"],
init_rc: ["android.hardware.graphics.composer@2.1-service.rc"],
- static_libs: ["libhwcomposer-client"],
shared_libs: [
"android.hardware.graphics.composer@2.1",
- "libbase",
"libbinder",
- "libcutils",
- "libfmq",
- "libhardware",
"libhidlbase",
"libhidltransport",
"liblog",
diff --git a/graphics/composer/2.1/default/ComposerBase.h b/graphics/composer/2.1/default/ComposerBase.h
deleted file mode 100644
index e1c9d33..0000000
--- a/graphics/composer/2.1/default/ComposerBase.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-
-#ifndef ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_BASE_H
-#define ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_BASE_H
-
-#include <android/hardware/graphics/composer/2.1/IComposer.h>
-#include <hardware/hwcomposer2.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_1 {
-namespace implementation {
-
-using android::hardware::graphics::common::V1_0::PixelFormat;
-using android::hardware::graphics::common::V1_0::Transform;
-using android::hardware::graphics::common::V1_0::Dataspace;
-using android::hardware::graphics::common::V1_0::ColorMode;
-using android::hardware::graphics::common::V1_0::ColorTransform;
-using android::hardware::graphics::common::V1_0::Hdr;
-
-class ComposerBase {
-public:
- virtual ~ComposerBase() {};
-
- virtual bool hasCapability(hwc2_capability_t capability) = 0;
-
- virtual void removeClient() = 0;
- virtual void enableCallback(bool enable) = 0;
- virtual uint32_t getMaxVirtualDisplayCount() = 0;
- virtual Error createVirtualDisplay(uint32_t width, uint32_t height,
- PixelFormat* format, Display* outDisplay) = 0;
- virtual Error destroyVirtualDisplay(Display display) = 0;
- virtual Error createLayer(Display display, Layer* outLayer) = 0;
- virtual Error destroyLayer(Display display, Layer layer) = 0;
-
- virtual Error getActiveConfig(Display display, Config* outConfig) = 0;
- virtual Error getClientTargetSupport(Display display,
- uint32_t width, uint32_t height,
- PixelFormat format, Dataspace dataspace) = 0;
- virtual Error getColorModes(Display display,
- hidl_vec<ColorMode>* outModes) = 0;
- virtual Error getDisplayAttribute(Display display, Config config,
- IComposerClient::Attribute attribute, int32_t* outValue) = 0;
- virtual Error getDisplayConfigs(Display display,
- hidl_vec<Config>* outConfigs) = 0;
- virtual Error getDisplayName(Display display, hidl_string* outName) = 0;
- virtual Error getDisplayType(Display display,
- IComposerClient::DisplayType* outType) = 0;
- virtual Error getDozeSupport(Display display, bool* outSupport) = 0;
- virtual Error getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes,
- float* outMaxLuminance, float* outMaxAverageLuminance,
- float* outMinLuminance) = 0;
-
- virtual Error setActiveConfig(Display display, Config config) = 0;
- virtual Error setColorMode(Display display, ColorMode mode) = 0;
- virtual Error setPowerMode(Display display,
- IComposerClient::PowerMode mode) = 0;
- virtual Error setVsyncEnabled(Display display,
- IComposerClient::Vsync enabled) = 0;
-
- virtual Error setColorTransform(Display display, const float* matrix,
- int32_t hint) = 0;
- virtual Error setClientTarget(Display display, buffer_handle_t target,
- int32_t acquireFence, int32_t dataspace,
- const std::vector<hwc_rect_t>& damage) = 0;
- virtual Error setOutputBuffer(Display display, buffer_handle_t buffer,
- int32_t releaseFence) = 0;
- virtual Error validateDisplay(Display display,
- std::vector<Layer>* outChangedLayers,
- std::vector<IComposerClient::Composition>* outCompositionTypes,
- uint32_t* outDisplayRequestMask,
- std::vector<Layer>* outRequestedLayers,
- std::vector<uint32_t>* outRequestMasks) = 0;
- virtual Error acceptDisplayChanges(Display display) = 0;
- virtual Error presentDisplay(Display display, int32_t* outPresentFence,
- std::vector<Layer>* outLayers,
- std::vector<int32_t>* outReleaseFences) = 0;
-
- virtual Error setLayerCursorPosition(Display display, Layer layer,
- int32_t x, int32_t y) = 0;
- virtual Error setLayerBuffer(Display display, Layer layer,
- buffer_handle_t buffer, int32_t acquireFence) = 0;
- virtual Error setLayerSurfaceDamage(Display display, Layer layer,
- const std::vector<hwc_rect_t>& damage) = 0;
- virtual Error setLayerBlendMode(Display display, Layer layer,
- int32_t mode) = 0;
- virtual Error setLayerColor(Display display, Layer layer,
- IComposerClient::Color color) = 0;
- virtual Error setLayerCompositionType(Display display, Layer layer,
- int32_t type) = 0;
- virtual Error setLayerDataspace(Display display, Layer layer,
- int32_t dataspace) = 0;
- virtual Error setLayerDisplayFrame(Display display, Layer layer,
- const hwc_rect_t& frame) = 0;
- virtual Error setLayerPlaneAlpha(Display display, Layer layer,
- float alpha) = 0;
- virtual Error setLayerSidebandStream(Display display, Layer layer,
- buffer_handle_t stream) = 0;
- virtual Error setLayerSourceCrop(Display display, Layer layer,
- const hwc_frect_t& crop) = 0;
- virtual Error setLayerTransform(Display display, Layer layer,
- int32_t transform) = 0;
- virtual Error setLayerVisibleRegion(Display display, Layer layer,
- const std::vector<hwc_rect_t>& visible) = 0;
- virtual Error setLayerZOrder(Display display, Layer layer,
- uint32_t z) = 0;
-};
-
-} // namespace implementation
-} // namespace V2_1
-} // namespace composer
-} // namespace graphics
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_BASE_H
diff --git a/graphics/composer/2.1/default/ComposerClient.cpp b/graphics/composer/2.1/default/ComposerClient.cpp
deleted file mode 100644
index 0fcb9de..0000000
--- a/graphics/composer/2.1/default/ComposerClient.cpp
+++ /dev/null
@@ -1,1205 +0,0 @@
-/*
- * Copyright 2016 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.
- */
-
-#define LOG_TAG "HwcPassthrough"
-
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <log/log.h>
-
-#include "ComposerBase.h"
-#include "ComposerClient.h"
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_1 {
-namespace implementation {
-
-namespace {
-
-using MapperError = android::hardware::graphics::mapper::V2_0::Error;
-using android::hardware::graphics::mapper::V2_0::IMapper;
-
-class HandleImporter {
-public:
- bool initialize()
- {
- // allow only one client
- if (mInitialized) {
- return false;
- }
-
- mMapper = IMapper::getService();
-
- mInitialized = true;
- return true;
- }
-
- void cleanup()
- {
- mMapper.clear();
- mInitialized = false;
- }
-
- // In IComposer, any buffer_handle_t is owned by the caller and we need to
- // make a clone for hwcomposer2. We also need to translate empty handle
- // to nullptr. This function does that, in-place.
- bool importBuffer(buffer_handle_t& handle)
- {
- if (!handle) {
- return true;
- }
-
- if (!handle->numFds && !handle->numInts) {
- handle = nullptr;
- return true;
- }
-
- MapperError error;
- buffer_handle_t importedHandle;
- mMapper->importBuffer(
- hidl_handle(handle),
- [&](const auto& tmpError, const auto& tmpBufferHandle) {
- error = tmpError;
- importedHandle = static_cast<buffer_handle_t>(tmpBufferHandle);
- });
- if (error != MapperError::NONE) {
- return false;
- }
-
- handle = importedHandle;
-
- return true;
- }
-
- void freeBuffer(buffer_handle_t handle)
- {
- if (!handle) {
- return;
- }
-
- mMapper->freeBuffer(const_cast<native_handle_t*>(handle));
- }
-
-private:
- bool mInitialized = false;
- sp<IMapper> mMapper;
-};
-
-HandleImporter sHandleImporter;
-
-} // anonymous namespace
-
-BufferCacheEntry::BufferCacheEntry()
- : mHandle(nullptr)
-{
-}
-
-BufferCacheEntry::BufferCacheEntry(BufferCacheEntry&& other)
-{
- mHandle = other.mHandle;
- other.mHandle = nullptr;
-}
-
-BufferCacheEntry& BufferCacheEntry::operator=(buffer_handle_t handle)
-{
- clear();
- mHandle = handle;
- return *this;
-}
-
-BufferCacheEntry::~BufferCacheEntry()
-{
- clear();
-}
-
-void BufferCacheEntry::clear()
-{
- if (mHandle) {
- sHandleImporter.freeBuffer(mHandle);
- }
-}
-
-ComposerClient::ComposerClient(ComposerBase& hal)
- : mHal(hal), mWriter(kWriterInitialSize)
-{
-}
-
-ComposerClient::~ComposerClient()
-{
- // We want to call hwc2_close here (and move hwc2_open to the
- // constructor), with the assumption that hwc2_close would
- //
- // - clean up all resources owned by the client
- // - make sure all displays are blank (since there is no layer)
- //
- // But since SF used to crash at this point, different hwcomposer2
- // implementations behave differently on hwc2_close. Our only portable
- // choice really is to abort(). But that is not an option anymore
- // because we might also have VTS or VR as clients that can come and go.
- //
- // Below we manually clean all resources (layers and virtual
- // displays), and perform a presentDisplay afterwards.
- ALOGW("destroying composer client");
-
- mHal.enableCallback(false);
-
- // no need to grab the mutex as any in-flight hwbinder call would have
- // kept the client alive
- for (const auto& dpy : mDisplayData) {
- ALOGW("destroying client resources for display %" PRIu64, dpy.first);
-
- for (const auto& ly : dpy.second.Layers) {
- mHal.destroyLayer(dpy.first, ly.first);
- }
-
- if (dpy.second.IsVirtual) {
- mHal.destroyVirtualDisplay(dpy.first);
- } else {
- ALOGW("performing a final presentDisplay");
-
- std::vector<Layer> changedLayers;
- std::vector<IComposerClient::Composition> compositionTypes;
- uint32_t displayRequestMask = 0;
- std::vector<Layer> requestedLayers;
- std::vector<uint32_t> requestMasks;
- mHal.validateDisplay(dpy.first, &changedLayers, &compositionTypes,
- &displayRequestMask, &requestedLayers, &requestMasks);
-
- mHal.acceptDisplayChanges(dpy.first);
-
- int32_t presentFence = -1;
- std::vector<Layer> releasedLayers;
- std::vector<int32_t> releaseFences;
- mHal.presentDisplay(dpy.first, &presentFence, &releasedLayers, &releaseFences);
- if (presentFence >= 0) {
- close(presentFence);
- }
- for (auto fence : releaseFences) {
- if (fence >= 0) {
- close(fence);
- }
- }
- }
- }
-
- mDisplayData.clear();
-
- sHandleImporter.cleanup();
-
- mHal.removeClient();
-
- ALOGW("removed composer client");
-}
-
-void ComposerClient::initialize()
-{
- mReader = createCommandReader();
- if (!sHandleImporter.initialize()) {
- LOG_ALWAYS_FATAL("failed to initialize handle importer");
- }
-}
-
-void ComposerClient::onHotplug(Display display,
- IComposerCallback::Connection connected)
-{
- {
- std::lock_guard<std::mutex> lock(mDisplayDataMutex);
-
- if (connected == IComposerCallback::Connection::CONNECTED) {
- mDisplayData.emplace(display, DisplayData(false));
- } else if (connected == IComposerCallback::Connection::DISCONNECTED) {
- mDisplayData.erase(display);
- }
- }
-
- auto ret = mCallback->onHotplug(display, connected);
- ALOGE_IF(!ret.isOk(), "failed to send onHotplug: %s",
- ret.description().c_str());
-}
-
-void ComposerClient::onRefresh(Display display)
-{
- auto ret = mCallback->onRefresh(display);
- ALOGE_IF(!ret.isOk(), "failed to send onRefresh: %s",
- ret.description().c_str());
-}
-
-void ComposerClient::onVsync(Display display, int64_t timestamp)
-{
- auto ret = mCallback->onVsync(display, timestamp);
- ALOGE_IF(!ret.isOk(), "failed to send onVsync: %s",
- ret.description().c_str());
-}
-
-Return<void> ComposerClient::registerCallback(
- const sp<IComposerCallback>& callback)
-{
- // no locking as we require this function to be called only once
- mCallback = callback;
- mHal.enableCallback(callback != nullptr);
-
- return Void();
-}
-
-Return<uint32_t> ComposerClient::getMaxVirtualDisplayCount()
-{
- return mHal.getMaxVirtualDisplayCount();
-}
-
-Return<void> ComposerClient::createVirtualDisplay(uint32_t width,
- uint32_t height, PixelFormat formatHint, uint32_t outputBufferSlotCount,
- createVirtualDisplay_cb hidl_cb)
-{
- Display display = 0;
- Error err = mHal.createVirtualDisplay(width, height,
- &formatHint, &display);
- if (err == Error::NONE) {
- std::lock_guard<std::mutex> lock(mDisplayDataMutex);
-
- auto dpy = mDisplayData.emplace(display, DisplayData(true)).first;
- dpy->second.OutputBuffers.resize(outputBufferSlotCount);
- }
-
- hidl_cb(err, display, formatHint);
- return Void();
-}
-
-Return<Error> ComposerClient::destroyVirtualDisplay(Display display)
-{
- Error err = mHal.destroyVirtualDisplay(display);
- if (err == Error::NONE) {
- std::lock_guard<std::mutex> lock(mDisplayDataMutex);
-
- mDisplayData.erase(display);
- }
-
- return err;
-}
-
-Return<void> ComposerClient::createLayer(Display display,
- uint32_t bufferSlotCount, createLayer_cb hidl_cb)
-{
- Layer layer = 0;
- Error err = mHal.createLayer(display, &layer);
- if (err == Error::NONE) {
- std::lock_guard<std::mutex> lock(mDisplayDataMutex);
- auto dpy = mDisplayData.find(display);
- // The display entry may have already been removed by onHotplug.
- if (dpy != mDisplayData.end()) {
- auto ly = dpy->second.Layers.emplace(layer, LayerBuffers()).first;
- ly->second.Buffers.resize(bufferSlotCount);
- } else {
- err = Error::BAD_DISPLAY;
- // Note: We do not destroy the layer on this error as the hotplug
- // disconnect invalidates the display id. The implementation should
- // ensure all layers for the display are destroyed.
- }
- }
-
- hidl_cb(err, layer);
- return Void();
-}
-
-Return<Error> ComposerClient::destroyLayer(Display display, Layer layer)
-{
- Error err = mHal.destroyLayer(display, layer);
- if (err == Error::NONE) {
- std::lock_guard<std::mutex> lock(mDisplayDataMutex);
-
- auto dpy = mDisplayData.find(display);
- // The display entry may have already been removed by onHotplug.
- if (dpy != mDisplayData.end()) {
- dpy->second.Layers.erase(layer);
- }
- }
-
- return err;
-}
-
-Return<void> ComposerClient::getActiveConfig(Display display,
- getActiveConfig_cb hidl_cb)
-{
- Config config = 0;
- Error err = mHal.getActiveConfig(display, &config);
-
- hidl_cb(err, config);
- return Void();
-}
-
-Return<Error> ComposerClient::getClientTargetSupport(Display display,
- uint32_t width, uint32_t height,
- PixelFormat format, Dataspace dataspace)
-{
- Error err = mHal.getClientTargetSupport(display,
- width, height, format, dataspace);
- return err;
-}
-
-Return<void> ComposerClient::getColorModes(Display display,
- getColorModes_cb hidl_cb)
-{
- hidl_vec<ColorMode> modes;
- Error err = mHal.getColorModes(display, &modes);
-
- hidl_cb(err, modes);
- return Void();
-}
-
-Return<void> ComposerClient::getDisplayAttribute(Display display,
- Config config, Attribute attribute,
- getDisplayAttribute_cb hidl_cb)
-{
- int32_t value = 0;
- Error err = mHal.getDisplayAttribute(display, config, attribute, &value);
-
- hidl_cb(err, value);
- return Void();
-}
-
-Return<void> ComposerClient::getDisplayConfigs(Display display,
- getDisplayConfigs_cb hidl_cb)
-{
- hidl_vec<Config> configs;
- Error err = mHal.getDisplayConfigs(display, &configs);
-
- hidl_cb(err, configs);
- return Void();
-}
-
-Return<void> ComposerClient::getDisplayName(Display display,
- getDisplayName_cb hidl_cb)
-{
- hidl_string name;
- Error err = mHal.getDisplayName(display, &name);
-
- hidl_cb(err, name);
- return Void();
-}
-
-Return<void> ComposerClient::getDisplayType(Display display,
- getDisplayType_cb hidl_cb)
-{
- DisplayType type = DisplayType::INVALID;
- Error err = mHal.getDisplayType(display, &type);
-
- hidl_cb(err, type);
- return Void();
-}
-
-Return<void> ComposerClient::getDozeSupport(Display display,
- getDozeSupport_cb hidl_cb)
-{
- bool support = false;
- Error err = mHal.getDozeSupport(display, &support);
-
- hidl_cb(err, support);
- return Void();
-}
-
-Return<void> ComposerClient::getHdrCapabilities(Display display,
- getHdrCapabilities_cb hidl_cb)
-{
- hidl_vec<Hdr> types;
- float max_lumi = 0.0f;
- float max_avg_lumi = 0.0f;
- float min_lumi = 0.0f;
- Error err = mHal.getHdrCapabilities(display, &types,
- &max_lumi, &max_avg_lumi, &min_lumi);
-
- hidl_cb(err, types, max_lumi, max_avg_lumi, min_lumi);
- return Void();
-}
-
-Return<Error> ComposerClient::setClientTargetSlotCount(Display display,
- uint32_t clientTargetSlotCount)
-{
- std::lock_guard<std::mutex> lock(mDisplayDataMutex);
-
- auto dpy = mDisplayData.find(display);
- if (dpy == mDisplayData.end()) {
- return Error::BAD_DISPLAY;
- }
-
- dpy->second.ClientTargets.resize(clientTargetSlotCount);
-
- return Error::NONE;
-}
-
-Return<Error> ComposerClient::setActiveConfig(Display display, Config config)
-{
- Error err = mHal.setActiveConfig(display, config);
- return err;
-}
-
-Return<Error> ComposerClient::setColorMode(Display display, ColorMode mode)
-{
- Error err = mHal.setColorMode(display, mode);
- return err;
-}
-
-Return<Error> ComposerClient::setPowerMode(Display display, PowerMode mode)
-{
- Error err = mHal.setPowerMode(display, mode);
- return err;
-}
-
-Return<Error> ComposerClient::setVsyncEnabled(Display display, Vsync enabled)
-{
- Error err = mHal.setVsyncEnabled(display, enabled);
- return err;
-}
-
-Return<Error> ComposerClient::setInputCommandQueue(
- const MQDescriptorSync<uint32_t>& descriptor)
-{
- std::lock_guard<std::mutex> lock(mCommandMutex);
- return mReader->setMQDescriptor(descriptor) ?
- Error::NONE : Error::NO_RESOURCES;
-}
-
-Return<void> ComposerClient::getOutputCommandQueue(
- getOutputCommandQueue_cb hidl_cb)
-{
- // no locking as we require this function to be called inside
- // executeCommands_cb
-
- auto outDescriptor = mWriter.getMQDescriptor();
- if (outDescriptor) {
- hidl_cb(Error::NONE, *outDescriptor);
- } else {
- hidl_cb(Error::NO_RESOURCES, CommandQueueType::Descriptor());
- }
-
- return Void();
-}
-
-Return<void> ComposerClient::executeCommands(uint32_t inLength,
- const hidl_vec<hidl_handle>& inHandles,
- executeCommands_cb hidl_cb)
-{
- std::lock_guard<std::mutex> lock(mCommandMutex);
-
- bool outChanged = false;
- uint32_t outLength = 0;
- hidl_vec<hidl_handle> outHandles;
-
- if (!mReader->readQueue(inLength, inHandles)) {
- hidl_cb(Error::BAD_PARAMETER, outChanged, outLength, outHandles);
- return Void();
- }
-
- Error err = mReader->parse();
- if (err == Error::NONE &&
- !mWriter.writeQueue(&outChanged, &outLength, &outHandles)) {
- err = Error::NO_RESOURCES;
- }
-
- hidl_cb(err, outChanged, outLength, outHandles);
-
- mReader->reset();
- mWriter.reset();
-
- return Void();
-}
-
-std::unique_ptr<ComposerClient::CommandReader>
-ComposerClient::createCommandReader()
-{
- return std::unique_ptr<ComposerClient::CommandReader>(
- new CommandReader(*this));
-}
-
-ComposerClient::CommandReader::CommandReader(ComposerClient& client)
- : mClient(client), mHal(client.mHal), mWriter(client.mWriter)
-{
-}
-
-ComposerClient::CommandReader::~CommandReader()
-{
-}
-
-Error ComposerClient::CommandReader::parse()
-{
- IComposerClient::Command command;
- uint16_t length = 0;
-
- while (!isEmpty()) {
- if (!beginCommand(&command, &length)) {
- break;
- }
-
- bool parsed = parseCommand(command, length);
- endCommand();
-
- if (!parsed) {
- ALOGE("failed to parse command 0x%x, length %" PRIu16,
- command, length);
- break;
- }
- }
-
- return (isEmpty()) ? Error::NONE : Error::BAD_PARAMETER;
-}
-
-bool ComposerClient::CommandReader::parseCommand(
- IComposerClient::Command command, uint16_t length) {
- switch (command) {
- case IComposerClient::Command::SELECT_DISPLAY:
- return parseSelectDisplay(length);
- case IComposerClient::Command::SELECT_LAYER:
- return parseSelectLayer(length);
- case IComposerClient::Command::SET_COLOR_TRANSFORM:
- return parseSetColorTransform(length);
- case IComposerClient::Command::SET_CLIENT_TARGET:
- return parseSetClientTarget(length);
- case IComposerClient::Command::SET_OUTPUT_BUFFER:
- return parseSetOutputBuffer(length);
- case IComposerClient::Command::VALIDATE_DISPLAY:
- return parseValidateDisplay(length);
- case IComposerClient::Command::PRESENT_OR_VALIDATE_DISPLAY:
- return parsePresentOrValidateDisplay(length);
- case IComposerClient::Command::ACCEPT_DISPLAY_CHANGES:
- return parseAcceptDisplayChanges(length);
- case IComposerClient::Command::PRESENT_DISPLAY:
- return parsePresentDisplay(length);
- case IComposerClient::Command::SET_LAYER_CURSOR_POSITION:
- return parseSetLayerCursorPosition(length);
- case IComposerClient::Command::SET_LAYER_BUFFER:
- return parseSetLayerBuffer(length);
- case IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE:
- return parseSetLayerSurfaceDamage(length);
- case IComposerClient::Command::SET_LAYER_BLEND_MODE:
- return parseSetLayerBlendMode(length);
- case IComposerClient::Command::SET_LAYER_COLOR:
- return parseSetLayerColor(length);
- case IComposerClient::Command::SET_LAYER_COMPOSITION_TYPE:
- return parseSetLayerCompositionType(length);
- case IComposerClient::Command::SET_LAYER_DATASPACE:
- return parseSetLayerDataspace(length);
- case IComposerClient::Command::SET_LAYER_DISPLAY_FRAME:
- return parseSetLayerDisplayFrame(length);
- case IComposerClient::Command::SET_LAYER_PLANE_ALPHA:
- return parseSetLayerPlaneAlpha(length);
- case IComposerClient::Command::SET_LAYER_SIDEBAND_STREAM:
- return parseSetLayerSidebandStream(length);
- case IComposerClient::Command::SET_LAYER_SOURCE_CROP:
- return parseSetLayerSourceCrop(length);
- case IComposerClient::Command::SET_LAYER_TRANSFORM:
- return parseSetLayerTransform(length);
- case IComposerClient::Command::SET_LAYER_VISIBLE_REGION:
- return parseSetLayerVisibleRegion(length);
- case IComposerClient::Command::SET_LAYER_Z_ORDER:
- return parseSetLayerZOrder(length);
- default:
- return false;
- }
-}
-
-bool ComposerClient::CommandReader::parseSelectDisplay(uint16_t length)
-{
- if (length != CommandWriterBase::kSelectDisplayLength) {
- return false;
- }
-
- mDisplay = read64();
- mWriter.selectDisplay(mDisplay);
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSelectLayer(uint16_t length)
-{
- if (length != CommandWriterBase::kSelectLayerLength) {
- return false;
- }
-
- mLayer = read64();
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSetColorTransform(uint16_t length)
-{
- if (length != CommandWriterBase::kSetColorTransformLength) {
- return false;
- }
-
- float matrix[16];
- for (int i = 0; i < 16; i++) {
- matrix[i] = readFloat();
- }
- auto transform = readSigned();
-
- auto err = mHal.setColorTransform(mDisplay, matrix, transform);
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSetClientTarget(uint16_t length)
-{
- // 4 parameters followed by N rectangles
- if ((length - 4) % 4 != 0) {
- return false;
- }
-
- bool useCache = false;
- auto slot = read();
- auto clientTarget = readHandle(&useCache);
- auto fence = readFence();
- auto dataspace = readSigned();
- auto damage = readRegion((length - 4) / 4);
- bool closeFence = true;
-
- auto err = lookupBuffer(BufferCache::CLIENT_TARGETS,
- slot, useCache, clientTarget, &clientTarget);
- if (err == Error::NONE) {
- err = mHal.setClientTarget(mDisplay, clientTarget, fence,
- dataspace, damage);
- auto updateBufErr = updateBuffer(BufferCache::CLIENT_TARGETS, slot,
- useCache, clientTarget);
- if (err == Error::NONE) {
- closeFence = false;
- err = updateBufErr;
- }
- }
- if (closeFence) {
- close(fence);
- }
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSetOutputBuffer(uint16_t length)
-{
- if (length != CommandWriterBase::kSetOutputBufferLength) {
- return false;
- }
-
- bool useCache = false;
- auto slot = read();
- auto outputBuffer = readHandle(&useCache);
- auto fence = readFence();
- bool closeFence = true;
-
- auto err = lookupBuffer(BufferCache::OUTPUT_BUFFERS,
- slot, useCache, outputBuffer, &outputBuffer);
- if (err == Error::NONE) {
- err = mHal.setOutputBuffer(mDisplay, outputBuffer, fence);
- auto updateBufErr = updateBuffer(BufferCache::OUTPUT_BUFFERS,
- slot, useCache, outputBuffer);
- if (err == Error::NONE) {
- closeFence = false;
- err = updateBufErr;
- }
- }
- if (closeFence) {
- close(fence);
- }
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseValidateDisplay(uint16_t length)
-{
- if (length != CommandWriterBase::kValidateDisplayLength) {
- return false;
- }
-
- std::vector<Layer> changedLayers;
- std::vector<IComposerClient::Composition> compositionTypes;
- uint32_t displayRequestMask = 0x0;
- std::vector<Layer> requestedLayers;
- std::vector<uint32_t> requestMasks;
-
- auto err = mHal.validateDisplay(mDisplay, &changedLayers,
- &compositionTypes, &displayRequestMask,
- &requestedLayers, &requestMasks);
- if (err == Error::NONE) {
- mWriter.setChangedCompositionTypes(changedLayers,
- compositionTypes);
- mWriter.setDisplayRequests(displayRequestMask,
- requestedLayers, requestMasks);
- } else {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parsePresentOrValidateDisplay(uint16_t length)
-{
- if (length != CommandWriterBase::kPresentOrValidateDisplayLength) {
- return false;
- }
-
- // First try to Present as is.
- if (mHal.hasCapability(HWC2_CAPABILITY_SKIP_VALIDATE)) {
- int presentFence = -1;
- std::vector<Layer> layers;
- std::vector<int> fences;
- auto err = mHal.presentDisplay(mDisplay, &presentFence, &layers, &fences);
- if (err == Error::NONE) {
- mWriter.setPresentOrValidateResult(1);
- mWriter.setPresentFence(presentFence);
- mWriter.setReleaseFences(layers, fences);
- return true;
- }
- }
-
- // Present has failed. We need to fallback to validate
- std::vector<Layer> changedLayers;
- std::vector<IComposerClient::Composition> compositionTypes;
- uint32_t displayRequestMask = 0x0;
- std::vector<Layer> requestedLayers;
- std::vector<uint32_t> requestMasks;
-
- auto err = mHal.validateDisplay(mDisplay, &changedLayers, &compositionTypes,
- &displayRequestMask, &requestedLayers, &requestMasks);
- if (err == Error::NONE) {
- mWriter.setPresentOrValidateResult(0);
- mWriter.setChangedCompositionTypes(changedLayers,
- compositionTypes);
- mWriter.setDisplayRequests(displayRequestMask,
- requestedLayers, requestMasks);
- } else {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseAcceptDisplayChanges(uint16_t length)
-{
- if (length != CommandWriterBase::kAcceptDisplayChangesLength) {
- return false;
- }
-
- auto err = mHal.acceptDisplayChanges(mDisplay);
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parsePresentDisplay(uint16_t length)
-{
- if (length != CommandWriterBase::kPresentDisplayLength) {
- return false;
- }
-
- int presentFence = -1;
- std::vector<Layer> layers;
- std::vector<int> fences;
- auto err = mHal.presentDisplay(mDisplay, &presentFence, &layers, &fences);
- if (err == Error::NONE) {
- mWriter.setPresentFence(presentFence);
- mWriter.setReleaseFences(layers, fences);
- } else {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSetLayerCursorPosition(uint16_t length)
-{
- if (length != CommandWriterBase::kSetLayerCursorPositionLength) {
- return false;
- }
-
- auto err = mHal.setLayerCursorPosition(mDisplay, mLayer,
- readSigned(), readSigned());
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSetLayerBuffer(uint16_t length)
-{
- if (length != CommandWriterBase::kSetLayerBufferLength) {
- return false;
- }
-
- bool useCache = false;
- auto slot = read();
- auto buffer = readHandle(&useCache);
- auto fence = readFence();
- bool closeFence = true;
-
- auto err = lookupBuffer(BufferCache::LAYER_BUFFERS,
- slot, useCache, buffer, &buffer);
- if (err == Error::NONE) {
- err = mHal.setLayerBuffer(mDisplay, mLayer, buffer, fence);
- auto updateBufErr = updateBuffer(BufferCache::LAYER_BUFFERS, slot,
- useCache, buffer);
- if (err == Error::NONE) {
- closeFence = false;
- err = updateBufErr;
- }
- }
- if (closeFence) {
- close(fence);
- }
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSetLayerSurfaceDamage(uint16_t length)
-{
- // N rectangles
- if (length % 4 != 0) {
- return false;
- }
-
- auto damage = readRegion(length / 4);
- auto err = mHal.setLayerSurfaceDamage(mDisplay, mLayer, damage);
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSetLayerBlendMode(uint16_t length)
-{
- if (length != CommandWriterBase::kSetLayerBlendModeLength) {
- return false;
- }
-
- auto err = mHal.setLayerBlendMode(mDisplay, mLayer, readSigned());
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSetLayerColor(uint16_t length)
-{
- if (length != CommandWriterBase::kSetLayerColorLength) {
- return false;
- }
-
- auto err = mHal.setLayerColor(mDisplay, mLayer, readColor());
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSetLayerCompositionType(
- uint16_t length)
-{
- if (length != CommandWriterBase::kSetLayerCompositionTypeLength) {
- return false;
- }
-
- auto err = mHal.setLayerCompositionType(mDisplay, mLayer, readSigned());
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSetLayerDataspace(uint16_t length)
-{
- if (length != CommandWriterBase::kSetLayerDataspaceLength) {
- return false;
- }
-
- auto err = mHal.setLayerDataspace(mDisplay, mLayer, readSigned());
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSetLayerDisplayFrame(uint16_t length)
-{
- if (length != CommandWriterBase::kSetLayerDisplayFrameLength) {
- return false;
- }
-
- auto err = mHal.setLayerDisplayFrame(mDisplay, mLayer, readRect());
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSetLayerPlaneAlpha(uint16_t length)
-{
- if (length != CommandWriterBase::kSetLayerPlaneAlphaLength) {
- return false;
- }
-
- auto err = mHal.setLayerPlaneAlpha(mDisplay, mLayer, readFloat());
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSetLayerSidebandStream(uint16_t length)
-{
- if (length != CommandWriterBase::kSetLayerSidebandStreamLength) {
- return false;
- }
-
- auto stream = readHandle();
-
- auto err = lookupLayerSidebandStream(stream, &stream);
- if (err == Error::NONE) {
- err = mHal.setLayerSidebandStream(mDisplay, mLayer, stream);
- auto updateErr = updateLayerSidebandStream(stream);
- if (err == Error::NONE) {
- err = updateErr;
- }
- }
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSetLayerSourceCrop(uint16_t length)
-{
- if (length != CommandWriterBase::kSetLayerSourceCropLength) {
- return false;
- }
-
- auto err = mHal.setLayerSourceCrop(mDisplay, mLayer, readFRect());
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSetLayerTransform(uint16_t length)
-{
- if (length != CommandWriterBase::kSetLayerTransformLength) {
- return false;
- }
-
- auto err = mHal.setLayerTransform(mDisplay, mLayer, readSigned());
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSetLayerVisibleRegion(uint16_t length)
-{
- // N rectangles
- if (length % 4 != 0) {
- return false;
- }
-
- auto region = readRegion(length / 4);
- auto err = mHal.setLayerVisibleRegion(mDisplay, mLayer, region);
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool ComposerClient::CommandReader::parseSetLayerZOrder(uint16_t length)
-{
- if (length != CommandWriterBase::kSetLayerZOrderLength) {
- return false;
- }
-
- auto err = mHal.setLayerZOrder(mDisplay, mLayer, read());
- if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-hwc_rect_t ComposerClient::CommandReader::readRect()
-{
- return hwc_rect_t{
- readSigned(),
- readSigned(),
- readSigned(),
- readSigned(),
- };
-}
-
-std::vector<hwc_rect_t> ComposerClient::CommandReader::readRegion(size_t count)
-{
- std::vector<hwc_rect_t> region;
- region.reserve(count);
- while (count > 0) {
- region.emplace_back(readRect());
- count--;
- }
-
- return region;
-}
-
-hwc_frect_t ComposerClient::CommandReader::readFRect()
-{
- return hwc_frect_t{
- readFloat(),
- readFloat(),
- readFloat(),
- readFloat(),
- };
-}
-
-Error ComposerClient::CommandReader::lookupBufferCacheEntryLocked(
- BufferCache cache, uint32_t slot, BufferCacheEntry** outEntry)
-{
- auto dpy = mClient.mDisplayData.find(mDisplay);
- if (dpy == mClient.mDisplayData.end()) {
- return Error::BAD_DISPLAY;
- }
-
- BufferCacheEntry* entry = nullptr;
- switch (cache) {
- case BufferCache::CLIENT_TARGETS:
- if (slot < dpy->second.ClientTargets.size()) {
- entry = &dpy->second.ClientTargets[slot];
- }
- break;
- case BufferCache::OUTPUT_BUFFERS:
- if (slot < dpy->second.OutputBuffers.size()) {
- entry = &dpy->second.OutputBuffers[slot];
- }
- break;
- case BufferCache::LAYER_BUFFERS:
- {
- auto ly = dpy->second.Layers.find(mLayer);
- if (ly == dpy->second.Layers.end()) {
- return Error::BAD_LAYER;
- }
- if (slot < ly->second.Buffers.size()) {
- entry = &ly->second.Buffers[slot];
- }
- }
- break;
- case BufferCache::LAYER_SIDEBAND_STREAMS:
- {
- auto ly = dpy->second.Layers.find(mLayer);
- if (ly == dpy->second.Layers.end()) {
- return Error::BAD_LAYER;
- }
- if (slot == 0) {
- entry = &ly->second.SidebandStream;
- }
- }
- break;
- default:
- break;
- }
-
- if (!entry) {
- ALOGW("invalid buffer slot %" PRIu32, slot);
- return Error::BAD_PARAMETER;
- }
-
- *outEntry = entry;
-
- return Error::NONE;
-}
-
-Error ComposerClient::CommandReader::lookupBuffer(BufferCache cache,
- uint32_t slot, bool useCache, buffer_handle_t handle,
- buffer_handle_t* outHandle)
-{
- if (useCache) {
- std::lock_guard<std::mutex> lock(mClient.mDisplayDataMutex);
-
- BufferCacheEntry* entry;
- Error error = lookupBufferCacheEntryLocked(cache, slot, &entry);
- if (error != Error::NONE) {
- return error;
- }
-
- // input handle is ignored
- *outHandle = entry->getHandle();
- } else if (cache == BufferCache::LAYER_SIDEBAND_STREAMS) {
- if (handle) {
- *outHandle = native_handle_clone(handle);
- if (*outHandle == nullptr) {
- return Error::NO_RESOURCES;
- }
- }
- } else {
- if (!sHandleImporter.importBuffer(handle)) {
- return Error::NO_RESOURCES;
- }
-
- *outHandle = handle;
- }
-
- return Error::NONE;
-}
-
-Error ComposerClient::CommandReader::updateBuffer(BufferCache cache,
- uint32_t slot, bool useCache, buffer_handle_t handle)
-{
- // handle was looked up from cache
- if (useCache) {
- return Error::NONE;
- }
-
- std::lock_guard<std::mutex> lock(mClient.mDisplayDataMutex);
-
- BufferCacheEntry* entry = nullptr;
- Error error = lookupBufferCacheEntryLocked(cache, slot, &entry);
- if (error != Error::NONE) {
- return error;
- }
-
- *entry = handle;
- return Error::NONE;
-}
-
-} // namespace implementation
-} // namespace V2_1
-} // namespace composer
-} // namespace graphics
-} // namespace hardware
-} // namespace android
diff --git a/graphics/composer/2.1/default/ComposerClient.h b/graphics/composer/2.1/default/ComposerClient.h
deleted file mode 100644
index 104ed5a..0000000
--- a/graphics/composer/2.1/default/ComposerClient.h
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright 2016 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.
- */
-
-#ifndef ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_CLIENT_H
-#define ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_CLIENT_H
-
-#include <mutex>
-#include <unordered_map>
-#include <vector>
-
-#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
-#include <hardware/hwcomposer2.h>
-#include "ComposerBase.h"
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_1 {
-namespace implementation {
-
-class BufferCacheEntry {
-public:
- BufferCacheEntry();
- BufferCacheEntry(BufferCacheEntry&& other);
-
- BufferCacheEntry(const BufferCacheEntry& other) = delete;
- BufferCacheEntry& operator=(const BufferCacheEntry& other) = delete;
-
- BufferCacheEntry& operator=(buffer_handle_t handle);
- ~BufferCacheEntry();
-
- buffer_handle_t getHandle() const { return mHandle; }
-
-private:
- void clear();
-
- buffer_handle_t mHandle;
-};
-
-class ComposerClient : public IComposerClient {
-public:
- ComposerClient(ComposerBase& hal);
- virtual ~ComposerClient();
-
- void initialize();
-
- void onHotplug(Display display, IComposerCallback::Connection connected);
- void onRefresh(Display display);
- void onVsync(Display display, int64_t timestamp);
-
- // IComposerClient interface
- Return<void> registerCallback(
- const sp<IComposerCallback>& callback) override;
- Return<uint32_t> getMaxVirtualDisplayCount() override;
- Return<void> createVirtualDisplay(uint32_t width, uint32_t height,
- PixelFormat formatHint, uint32_t outputBufferSlotCount,
- createVirtualDisplay_cb hidl_cb) override;
- Return<Error> destroyVirtualDisplay(Display display) override;
- Return<void> createLayer(Display display, uint32_t bufferSlotCount,
- createLayer_cb hidl_cb) override;
- Return<Error> destroyLayer(Display display, Layer layer) override;
- Return<void> getActiveConfig(Display display,
- getActiveConfig_cb hidl_cb) override;
- Return<Error> getClientTargetSupport(Display display,
- uint32_t width, uint32_t height,
- PixelFormat format, Dataspace dataspace) override;
- Return<void> getColorModes(Display display,
- getColorModes_cb hidl_cb) override;
- Return<void> getDisplayAttribute(Display display,
- Config config, Attribute attribute,
- getDisplayAttribute_cb hidl_cb) override;
- Return<void> getDisplayConfigs(Display display,
- getDisplayConfigs_cb hidl_cb) override;
- Return<void> getDisplayName(Display display,
- getDisplayName_cb hidl_cb) override;
- Return<void> getDisplayType(Display display,
- getDisplayType_cb hidl_cb) override;
- Return<void> getDozeSupport(Display display,
- getDozeSupport_cb hidl_cb) override;
- Return<void> getHdrCapabilities(Display display,
- getHdrCapabilities_cb hidl_cb) override;
- Return<Error> setActiveConfig(Display display, Config config) override;
- Return<Error> setColorMode(Display display, ColorMode mode) override;
- Return<Error> setPowerMode(Display display, PowerMode mode) override;
- Return<Error> setVsyncEnabled(Display display, Vsync enabled) override;
- Return<Error> setClientTargetSlotCount(Display display,
- uint32_t clientTargetSlotCount) override;
- Return<Error> setInputCommandQueue(
- const MQDescriptorSync<uint32_t>& descriptor) override;
- Return<void> getOutputCommandQueue(
- getOutputCommandQueue_cb hidl_cb) override;
- Return<void> executeCommands(uint32_t inLength,
- const hidl_vec<hidl_handle>& inHandles,
- executeCommands_cb hidl_cb) override;
-
-protected:
- struct LayerBuffers {
- std::vector<BufferCacheEntry> Buffers;
- // the handle is a sideband stream handle, not a buffer handle
- BufferCacheEntry SidebandStream;
- };
-
- struct DisplayData {
- bool IsVirtual;
-
- std::vector<BufferCacheEntry> ClientTargets;
- std::vector<BufferCacheEntry> OutputBuffers;
-
- std::unordered_map<Layer, LayerBuffers> Layers;
-
- DisplayData(bool isVirtual) : IsVirtual(isVirtual) {}
- };
-
- class CommandReader : public CommandReaderBase {
- public:
- CommandReader(ComposerClient& client);
- virtual ~CommandReader();
-
- Error parse();
-
- protected:
- virtual bool parseCommand(IComposerClient::Command command,
- uint16_t length);
-
- bool parseSelectDisplay(uint16_t length);
- bool parseSelectLayer(uint16_t length);
- bool parseSetColorTransform(uint16_t length);
- bool parseSetClientTarget(uint16_t length);
- bool parseSetOutputBuffer(uint16_t length);
- bool parseValidateDisplay(uint16_t length);
- bool parsePresentOrValidateDisplay(uint16_t length);
- bool parseAcceptDisplayChanges(uint16_t length);
- bool parsePresentDisplay(uint16_t length);
- bool parseSetLayerCursorPosition(uint16_t length);
- bool parseSetLayerBuffer(uint16_t length);
- bool parseSetLayerSurfaceDamage(uint16_t length);
- bool parseSetLayerBlendMode(uint16_t length);
- bool parseSetLayerColor(uint16_t length);
- bool parseSetLayerCompositionType(uint16_t length);
- bool parseSetLayerDataspace(uint16_t length);
- bool parseSetLayerDisplayFrame(uint16_t length);
- bool parseSetLayerPlaneAlpha(uint16_t length);
- bool parseSetLayerSidebandStream(uint16_t length);
- bool parseSetLayerSourceCrop(uint16_t length);
- bool parseSetLayerTransform(uint16_t length);
- bool parseSetLayerVisibleRegion(uint16_t length);
- bool parseSetLayerZOrder(uint16_t length);
-
- hwc_rect_t readRect();
- std::vector<hwc_rect_t> readRegion(size_t count);
- hwc_frect_t readFRect();
-
- enum class BufferCache {
- CLIENT_TARGETS,
- OUTPUT_BUFFERS,
- LAYER_BUFFERS,
- LAYER_SIDEBAND_STREAMS,
- };
- Error lookupBufferCacheEntryLocked(BufferCache cache, uint32_t slot,
- BufferCacheEntry** outEntry);
- Error lookupBuffer(BufferCache cache, uint32_t slot,
- bool useCache, buffer_handle_t handle,
- buffer_handle_t* outHandle);
- Error updateBuffer(BufferCache cache, uint32_t slot,
- bool useCache, buffer_handle_t handle);
-
- Error lookupLayerSidebandStream(buffer_handle_t handle,
- buffer_handle_t* outHandle)
- {
- return lookupBuffer(BufferCache::LAYER_SIDEBAND_STREAMS,
- 0, false, handle, outHandle);
- }
- Error updateLayerSidebandStream(buffer_handle_t handle)
- {
- return updateBuffer(BufferCache::LAYER_SIDEBAND_STREAMS,
- 0, false, handle);
- }
-
- ComposerClient& mClient;
- ComposerBase& mHal;
- CommandWriterBase& mWriter;
-
- Display mDisplay;
- Layer mLayer;
- };
-
- virtual std::unique_ptr<CommandReader> createCommandReader();
-
- ComposerBase& mHal;
-
- // 64KiB minus a small space for metadata such as read/write pointers
- static constexpr size_t kWriterInitialSize =
- 64 * 1024 / sizeof(uint32_t) - 16;
- std::mutex mCommandMutex;
- std::unique_ptr<CommandReader> mReader;
- CommandWriterBase mWriter;
-
- sp<IComposerCallback> mCallback;
-
- std::mutex mDisplayDataMutex;
- std::unordered_map<Display, DisplayData> mDisplayData;
-};
-
-} // namespace implementation
-} // namespace V2_1
-} // namespace composer
-} // namespace graphics
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_CLIENT_H
diff --git a/graphics/composer/2.1/default/Hwc.cpp b/graphics/composer/2.1/default/Hwc.cpp
deleted file mode 100644
index cb393ec..0000000
--- a/graphics/composer/2.1/default/Hwc.cpp
+++ /dev/null
@@ -1,817 +0,0 @@
-/*
- * Copyright 2016 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.
- */
-
-#define LOG_TAG "HwcPassthrough"
-
-#include "Hwc.h"
-
-#include <chrono>
-#include <type_traits>
-#include <log/log.h>
-
-#include "ComposerClient.h"
-#include "hardware/fb.h"
-#include "hardware/hwcomposer.h"
-#include "hwc2on1adapter/HWC2On1Adapter.h"
-#include "hwc2onfbadapter/HWC2OnFbAdapter.h"
-
-using namespace std::chrono_literals;
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_1 {
-namespace implementation {
-
-HwcHal::HwcHal(const hw_module_t* module)
- : mDevice(nullptr), mDispatch(), mMustValidateDisplay(true), mAdapter() {
- uint32_t majorVersion;
- if (module->id && strcmp(module->id, GRALLOC_HARDWARE_MODULE_ID) == 0) {
- majorVersion = initWithFb(module);
- } else {
- majorVersion = initWithHwc(module);
- }
-
- initCapabilities();
- if (majorVersion >= 2 && hasCapability(HWC2_CAPABILITY_PRESENT_FENCE_IS_NOT_RELIABLE)) {
- ALOGE("Present fence must be reliable from HWC2 on.");
- abort();
- }
-
- initDispatch();
-}
-
-HwcHal::~HwcHal()
-{
- hwc2_close(mDevice);
-}
-
-uint32_t HwcHal::initWithHwc(const hw_module_t* module)
-{
- // Determine what kind of module is available (HWC2 vs HWC1.X).
- hw_device_t* device = nullptr;
- int error = module->methods->open(module, HWC_HARDWARE_COMPOSER, &device);
- if (error != 0) {
- ALOGE("Failed to open HWC device (%s), aborting", strerror(-error));
- abort();
- }
- uint32_t majorVersion = (device->version >> 24) & 0xF;
-
- // If we don't have a HWC2, we need to wrap whatever we have in an adapter.
- if (majorVersion != 2) {
- uint32_t minorVersion = device->version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK;
- minorVersion = (minorVersion >> 16) & 0xF;
- ALOGI("Found HWC implementation v%d.%d", majorVersion, minorVersion);
- if (minorVersion < 1) {
- ALOGE("Cannot adapt to HWC version %d.%d. Minimum supported is 1.1",
- majorVersion, minorVersion);
- abort();
- }
- mAdapter = std::make_unique<HWC2On1Adapter>(
- reinterpret_cast<hwc_composer_device_1*>(device));
-
- // Place the adapter in front of the device module.
- mDevice = mAdapter.get();
- } else {
- mDevice = reinterpret_cast<hwc2_device_t*>(device);
- }
-
- return majorVersion;
-}
-
-uint32_t HwcHal::initWithFb(const hw_module_t* module)
-{
- framebuffer_device_t* fb_device;
- int error = framebuffer_open(module, &fb_device);
- if (error != 0) {
- ALOGE("Failed to open FB device (%s), aborting", strerror(-error));
- abort();
- }
-
- mFbAdapter = std::make_unique<HWC2OnFbAdapter>(fb_device);
- mDevice = mFbAdapter.get();
-
- return 0;
-}
-
-void HwcHal::initCapabilities()
-{
- uint32_t count = 0;
- mDevice->getCapabilities(mDevice, &count, nullptr);
-
- std::vector<int32_t> caps(count);
- mDevice->getCapabilities(mDevice, &count, caps.data());
- caps.resize(count);
-
- mCapabilities.reserve(count);
- for (auto cap : caps) {
- mCapabilities.insert(static_cast<hwc2_capability_t>(cap));
- }
-}
-
-template<typename T>
-void HwcHal::initDispatch(hwc2_function_descriptor_t desc, T* outPfn)
-{
- auto pfn = mDevice->getFunction(mDevice, desc);
- if (!pfn) {
- LOG_ALWAYS_FATAL("failed to get hwcomposer2 function %d", desc);
- }
-
- *outPfn = reinterpret_cast<T>(pfn);
-}
-
-void HwcHal::initDispatch()
-{
- initDispatch(HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES,
- &mDispatch.acceptDisplayChanges);
- initDispatch(HWC2_FUNCTION_CREATE_LAYER, &mDispatch.createLayer);
- initDispatch(HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY,
- &mDispatch.createVirtualDisplay);
- initDispatch(HWC2_FUNCTION_DESTROY_LAYER, &mDispatch.destroyLayer);
- initDispatch(HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY,
- &mDispatch.destroyVirtualDisplay);
- initDispatch(HWC2_FUNCTION_DUMP, &mDispatch.dump);
- initDispatch(HWC2_FUNCTION_GET_ACTIVE_CONFIG, &mDispatch.getActiveConfig);
- initDispatch(HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES,
- &mDispatch.getChangedCompositionTypes);
- initDispatch(HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT,
- &mDispatch.getClientTargetSupport);
- initDispatch(HWC2_FUNCTION_GET_COLOR_MODES, &mDispatch.getColorModes);
- initDispatch(HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE,
- &mDispatch.getDisplayAttribute);
- initDispatch(HWC2_FUNCTION_GET_DISPLAY_CONFIGS,
- &mDispatch.getDisplayConfigs);
- initDispatch(HWC2_FUNCTION_GET_DISPLAY_NAME, &mDispatch.getDisplayName);
- initDispatch(HWC2_FUNCTION_GET_DISPLAY_REQUESTS,
- &mDispatch.getDisplayRequests);
- initDispatch(HWC2_FUNCTION_GET_DISPLAY_TYPE, &mDispatch.getDisplayType);
- initDispatch(HWC2_FUNCTION_GET_DOZE_SUPPORT, &mDispatch.getDozeSupport);
- initDispatch(HWC2_FUNCTION_GET_HDR_CAPABILITIES,
- &mDispatch.getHdrCapabilities);
- initDispatch(HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT,
- &mDispatch.getMaxVirtualDisplayCount);
- initDispatch(HWC2_FUNCTION_GET_RELEASE_FENCES,
- &mDispatch.getReleaseFences);
- initDispatch(HWC2_FUNCTION_PRESENT_DISPLAY, &mDispatch.presentDisplay);
- initDispatch(HWC2_FUNCTION_REGISTER_CALLBACK,
- &mDispatch.registerCallback);
- initDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG, &mDispatch.setActiveConfig);
- initDispatch(HWC2_FUNCTION_SET_CLIENT_TARGET, &mDispatch.setClientTarget);
- initDispatch(HWC2_FUNCTION_SET_COLOR_MODE, &mDispatch.setColorMode);
- initDispatch(HWC2_FUNCTION_SET_COLOR_TRANSFORM,
- &mDispatch.setColorTransform);
- initDispatch(HWC2_FUNCTION_SET_CURSOR_POSITION,
- &mDispatch.setCursorPosition);
- initDispatch(HWC2_FUNCTION_SET_LAYER_BLEND_MODE,
- &mDispatch.setLayerBlendMode);
- initDispatch(HWC2_FUNCTION_SET_LAYER_BUFFER, &mDispatch.setLayerBuffer);
- initDispatch(HWC2_FUNCTION_SET_LAYER_COLOR, &mDispatch.setLayerColor);
- initDispatch(HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE,
- &mDispatch.setLayerCompositionType);
- initDispatch(HWC2_FUNCTION_SET_LAYER_DATASPACE,
- &mDispatch.setLayerDataspace);
- initDispatch(HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME,
- &mDispatch.setLayerDisplayFrame);
- initDispatch(HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA,
- &mDispatch.setLayerPlaneAlpha);
-
- if (hasCapability(HWC2_CAPABILITY_SIDEBAND_STREAM)) {
- initDispatch(HWC2_FUNCTION_SET_LAYER_SIDEBAND_STREAM,
- &mDispatch.setLayerSidebandStream);
- }
-
- initDispatch(HWC2_FUNCTION_SET_LAYER_SOURCE_CROP,
- &mDispatch.setLayerSourceCrop);
- initDispatch(HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE,
- &mDispatch.setLayerSurfaceDamage);
- initDispatch(HWC2_FUNCTION_SET_LAYER_TRANSFORM,
- &mDispatch.setLayerTransform);
- initDispatch(HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION,
- &mDispatch.setLayerVisibleRegion);
- initDispatch(HWC2_FUNCTION_SET_LAYER_Z_ORDER, &mDispatch.setLayerZOrder);
- initDispatch(HWC2_FUNCTION_SET_OUTPUT_BUFFER, &mDispatch.setOutputBuffer);
- initDispatch(HWC2_FUNCTION_SET_POWER_MODE, &mDispatch.setPowerMode);
- initDispatch(HWC2_FUNCTION_SET_VSYNC_ENABLED, &mDispatch.setVsyncEnabled);
- initDispatch(HWC2_FUNCTION_VALIDATE_DISPLAY, &mDispatch.validateDisplay);
-}
-
-bool HwcHal::hasCapability(hwc2_capability_t capability) {
- return (mCapabilities.count(capability) > 0);
-}
-
-Return<void> HwcHal::getCapabilities(getCapabilities_cb hidl_cb)
-{
- std::vector<Capability> caps;
- caps.reserve(mCapabilities.size());
- for (auto cap : mCapabilities) {
- switch (cap) {
- case HWC2_CAPABILITY_SIDEBAND_STREAM:
- case HWC2_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM:
- case HWC2_CAPABILITY_PRESENT_FENCE_IS_NOT_RELIABLE:
- caps.push_back(static_cast<Capability>(cap));
- break;
- default:
- // not all HWC2 caps are defined in HIDL
- break;
- }
- }
-
- hidl_vec<Capability> caps_reply;
- caps_reply.setToExternal(caps.data(), caps.size());
- hidl_cb(caps_reply);
-
- return Void();
-}
-
-Return<void> HwcHal::dumpDebugInfo(dumpDebugInfo_cb hidl_cb)
-{
- uint32_t len = 0;
- mDispatch.dump(mDevice, &len, nullptr);
-
- std::vector<char> buf(len + 1);
- mDispatch.dump(mDevice, &len, buf.data());
- buf.resize(len + 1);
- buf[len] = '\0';
-
- hidl_string buf_reply;
- buf_reply.setToExternal(buf.data(), len);
- hidl_cb(buf_reply);
-
- return Void();
-}
-
-Return<void> HwcHal::createClient(createClient_cb hidl_cb)
-{
- Error err = Error::NONE;
- sp<ComposerClient> client;
-
- {
- std::unique_lock<std::mutex> lock(mClientMutex);
-
- if (mClient != nullptr) {
- // In surface flinger we delete a composer client on one thread and
- // then create a new client on another thread. Although surface
- // flinger ensures the calls are made in that sequence (destroy and
- // then create), sometimes the calls land in the composer service
- // inverted (create and then destroy). Wait for a brief period to
- // see if the existing client is destroyed.
- ALOGI("HwcHal::createClient: Client already exists. Waiting for"
- " it to be destroyed.");
- mClientDestroyedWait.wait_for(lock, 1s,
- [this] { return mClient == nullptr; });
- std::string doneMsg = mClient == nullptr ?
- "Existing client was destroyed." :
- "Existing client was never destroyed!";
- ALOGI("HwcHal::createClient: Done waiting. %s", doneMsg.c_str());
- }
-
- // only one client is allowed
- if (mClient == nullptr) {
- client = new ComposerClient(*this);
- client->initialize();
- mClient = client;
- } else {
- err = Error::NO_RESOURCES;
- }
- }
-
- hidl_cb(err, client);
-
- return Void();
-}
-
-sp<ComposerClient> HwcHal::getClient()
-{
- std::lock_guard<std::mutex> lock(mClientMutex);
- return (mClient != nullptr) ? mClient.promote() : nullptr;
-}
-
-void HwcHal::removeClient()
-{
- std::lock_guard<std::mutex> lock(mClientMutex);
- mClient = nullptr;
- mClientDestroyedWait.notify_all();
-}
-
-void HwcHal::hotplugHook(hwc2_callback_data_t callbackData,
- hwc2_display_t display, int32_t connected)
-{
- auto hal = reinterpret_cast<HwcHal*>(callbackData);
- auto client = hal->getClient();
- if (client != nullptr) {
- client->onHotplug(display,
- static_cast<IComposerCallback::Connection>(connected));
- }
-}
-
-void HwcHal::refreshHook(hwc2_callback_data_t callbackData,
- hwc2_display_t display)
-{
- auto hal = reinterpret_cast<HwcHal*>(callbackData);
- hal->mMustValidateDisplay = true;
-
- auto client = hal->getClient();
- if (client != nullptr) {
- client->onRefresh(display);
- }
-}
-
-void HwcHal::vsyncHook(hwc2_callback_data_t callbackData,
- hwc2_display_t display, int64_t timestamp)
-{
- auto hal = reinterpret_cast<HwcHal*>(callbackData);
- auto client = hal->getClient();
- if (client != nullptr) {
- client->onVsync(display, timestamp);
- }
-}
-
-void HwcHal::enableCallback(bool enable)
-{
- if (enable) {
- mMustValidateDisplay = true;
-
- mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this,
- reinterpret_cast<hwc2_function_pointer_t>(hotplugHook));
- mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this,
- reinterpret_cast<hwc2_function_pointer_t>(refreshHook));
- mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this,
- reinterpret_cast<hwc2_function_pointer_t>(vsyncHook));
- } else {
- mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this,
- nullptr);
- mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this,
- nullptr);
- mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this,
- nullptr);
- }
-}
-
-uint32_t HwcHal::getMaxVirtualDisplayCount()
-{
- return mDispatch.getMaxVirtualDisplayCount(mDevice);
-}
-
-Error HwcHal::createVirtualDisplay(uint32_t width, uint32_t height,
- PixelFormat* format, Display* outDisplay)
-{
- int32_t hwc_format = static_cast<int32_t>(*format);
- int32_t err = mDispatch.createVirtualDisplay(mDevice, width, height,
- &hwc_format, outDisplay);
- *format = static_cast<PixelFormat>(hwc_format);
-
- return static_cast<Error>(err);
-}
-
-Error HwcHal::destroyVirtualDisplay(Display display)
-{
- int32_t err = mDispatch.destroyVirtualDisplay(mDevice, display);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::createLayer(Display display, Layer* outLayer)
-{
- int32_t err = mDispatch.createLayer(mDevice, display, outLayer);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::destroyLayer(Display display, Layer layer)
-{
- int32_t err = mDispatch.destroyLayer(mDevice, display, layer);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::getActiveConfig(Display display, Config* outConfig)
-{
- int32_t err = mDispatch.getActiveConfig(mDevice, display, outConfig);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::getClientTargetSupport(Display display,
- uint32_t width, uint32_t height,
- PixelFormat format, Dataspace dataspace)
-{
- int32_t err = mDispatch.getClientTargetSupport(mDevice, display,
- width, height, static_cast<int32_t>(format),
- static_cast<int32_t>(dataspace));
- return static_cast<Error>(err);
-}
-
-Error HwcHal::getColorModes(Display display, hidl_vec<ColorMode>* outModes)
-{
- uint32_t count = 0;
- int32_t err = mDispatch.getColorModes(mDevice, display, &count, nullptr);
- if (err != HWC2_ERROR_NONE) {
- return static_cast<Error>(err);
- }
-
- outModes->resize(count);
- err = mDispatch.getColorModes(mDevice, display, &count,
- reinterpret_cast<std::underlying_type<ColorMode>::type*>(
- outModes->data()));
- if (err != HWC2_ERROR_NONE) {
- *outModes = hidl_vec<ColorMode>();
- return static_cast<Error>(err);
- }
-
- return Error::NONE;
-}
-
-Error HwcHal::getDisplayAttribute(Display display, Config config,
- IComposerClient::Attribute attribute, int32_t* outValue)
-{
- int32_t err = mDispatch.getDisplayAttribute(mDevice, display, config,
- static_cast<int32_t>(attribute), outValue);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs)
-{
- uint32_t count = 0;
- int32_t err = mDispatch.getDisplayConfigs(mDevice, display,
- &count, nullptr);
- if (err != HWC2_ERROR_NONE) {
- return static_cast<Error>(err);
- }
-
- outConfigs->resize(count);
- err = mDispatch.getDisplayConfigs(mDevice, display,
- &count, outConfigs->data());
- if (err != HWC2_ERROR_NONE) {
- *outConfigs = hidl_vec<Config>();
- return static_cast<Error>(err);
- }
-
- return Error::NONE;
-}
-
-Error HwcHal::getDisplayName(Display display, hidl_string* outName)
-{
- uint32_t count = 0;
- int32_t err = mDispatch.getDisplayName(mDevice, display, &count, nullptr);
- if (err != HWC2_ERROR_NONE) {
- return static_cast<Error>(err);
- }
-
- std::vector<char> buf(count + 1);
- err = mDispatch.getDisplayName(mDevice, display, &count, buf.data());
- if (err != HWC2_ERROR_NONE) {
- return static_cast<Error>(err);
- }
- buf.resize(count + 1);
- buf[count] = '\0';
-
- *outName = buf.data();
-
- return Error::NONE;
-}
-
-Error HwcHal::getDisplayType(Display display,
- IComposerClient::DisplayType* outType)
-{
- int32_t hwc_type = HWC2_DISPLAY_TYPE_INVALID;
- int32_t err = mDispatch.getDisplayType(mDevice, display, &hwc_type);
- *outType = static_cast<IComposerClient::DisplayType>(hwc_type);
-
- return static_cast<Error>(err);
-}
-
-Error HwcHal::getDozeSupport(Display display, bool* outSupport)
-{
- int32_t hwc_support = 0;
- int32_t err = mDispatch.getDozeSupport(mDevice, display, &hwc_support);
- *outSupport = hwc_support;
-
- return static_cast<Error>(err);
-}
-
-Error HwcHal::getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes,
- float* outMaxLuminance, float* outMaxAverageLuminance,
- float* outMinLuminance)
-{
- uint32_t count = 0;
- int32_t err = mDispatch.getHdrCapabilities(mDevice, display, &count,
- nullptr, outMaxLuminance, outMaxAverageLuminance,
- outMinLuminance);
- if (err != HWC2_ERROR_NONE) {
- return static_cast<Error>(err);
- }
-
- outTypes->resize(count);
- err = mDispatch.getHdrCapabilities(mDevice, display, &count,
- reinterpret_cast<std::underlying_type<Hdr>::type*>(
- outTypes->data()), outMaxLuminance,
- outMaxAverageLuminance, outMinLuminance);
- if (err != HWC2_ERROR_NONE) {
- *outTypes = hidl_vec<Hdr>();
- return static_cast<Error>(err);
- }
-
- return Error::NONE;
-}
-
-Error HwcHal::setActiveConfig(Display display, Config config)
-{
- int32_t err = mDispatch.setActiveConfig(mDevice, display, config);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setColorMode(Display display, ColorMode mode)
-{
- int32_t err = mDispatch.setColorMode(mDevice, display,
- static_cast<int32_t>(mode));
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setPowerMode(Display display, IComposerClient::PowerMode mode)
-{
- int32_t err = mDispatch.setPowerMode(mDevice, display,
- static_cast<int32_t>(mode));
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setVsyncEnabled(Display display, IComposerClient::Vsync enabled)
-{
- int32_t err = mDispatch.setVsyncEnabled(mDevice, display,
- static_cast<int32_t>(enabled));
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setColorTransform(Display display, const float* matrix,
- int32_t hint)
-{
- int32_t err = mDispatch.setColorTransform(mDevice, display, matrix, hint);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setClientTarget(Display display, buffer_handle_t target,
- int32_t acquireFence, int32_t dataspace,
- const std::vector<hwc_rect_t>& damage)
-{
- hwc_region region = { damage.size(), damage.data() };
- int32_t err = mDispatch.setClientTarget(mDevice, display, target,
- acquireFence, dataspace, region);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setOutputBuffer(Display display, buffer_handle_t buffer,
- int32_t releaseFence)
-{
- int32_t err = mDispatch.setOutputBuffer(mDevice, display, buffer,
- releaseFence);
- // unlike in setClientTarget, releaseFence is owned by us
- if (err == HWC2_ERROR_NONE && releaseFence >= 0) {
- close(releaseFence);
- }
-
- return static_cast<Error>(err);
-}
-
-Error HwcHal::validateDisplay(Display display,
- std::vector<Layer>* outChangedLayers,
- std::vector<IComposerClient::Composition>* outCompositionTypes,
- uint32_t* outDisplayRequestMask,
- std::vector<Layer>* outRequestedLayers,
- std::vector<uint32_t>* outRequestMasks)
-{
- uint32_t types_count = 0;
- uint32_t reqs_count = 0;
- int32_t err = mDispatch.validateDisplay(mDevice, display,
- &types_count, &reqs_count);
- mMustValidateDisplay = false;
-
- if (err != HWC2_ERROR_NONE && err != HWC2_ERROR_HAS_CHANGES) {
- return static_cast<Error>(err);
- }
-
- err = mDispatch.getChangedCompositionTypes(mDevice, display,
- &types_count, nullptr, nullptr);
- if (err != HWC2_ERROR_NONE) {
- return static_cast<Error>(err);
- }
-
- outChangedLayers->resize(types_count);
- outCompositionTypes->resize(types_count);
- err = mDispatch.getChangedCompositionTypes(mDevice, display,
- &types_count, outChangedLayers->data(),
- reinterpret_cast<
- std::underlying_type<IComposerClient::Composition>::type*>(
- outCompositionTypes->data()));
- if (err != HWC2_ERROR_NONE) {
- outChangedLayers->clear();
- outCompositionTypes->clear();
- return static_cast<Error>(err);
- }
-
- int32_t display_reqs = 0;
- err = mDispatch.getDisplayRequests(mDevice, display, &display_reqs,
- &reqs_count, nullptr, nullptr);
- if (err != HWC2_ERROR_NONE) {
- outChangedLayers->clear();
- outCompositionTypes->clear();
- return static_cast<Error>(err);
- }
-
- outRequestedLayers->resize(reqs_count);
- outRequestMasks->resize(reqs_count);
- err = mDispatch.getDisplayRequests(mDevice, display, &display_reqs,
- &reqs_count, outRequestedLayers->data(),
- reinterpret_cast<int32_t*>(outRequestMasks->data()));
- if (err != HWC2_ERROR_NONE) {
- outChangedLayers->clear();
- outCompositionTypes->clear();
-
- outRequestedLayers->clear();
- outRequestMasks->clear();
- return static_cast<Error>(err);
- }
-
- *outDisplayRequestMask = display_reqs;
-
- return static_cast<Error>(err);
-}
-
-Error HwcHal::acceptDisplayChanges(Display display)
-{
- int32_t err = mDispatch.acceptDisplayChanges(mDevice, display);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::presentDisplay(Display display, int32_t* outPresentFence,
- std::vector<Layer>* outLayers, std::vector<int32_t>* outReleaseFences)
-{
- if (mMustValidateDisplay) {
- return Error::NOT_VALIDATED;
- }
-
- *outPresentFence = -1;
- int32_t err = mDispatch.presentDisplay(mDevice, display, outPresentFence);
- if (err != HWC2_ERROR_NONE) {
- return static_cast<Error>(err);
- }
-
- uint32_t count = 0;
- err = mDispatch.getReleaseFences(mDevice, display, &count,
- nullptr, nullptr);
- if (err != HWC2_ERROR_NONE) {
- ALOGW("failed to get release fences");
- return Error::NONE;
- }
-
- outLayers->resize(count);
- outReleaseFences->resize(count);
- err = mDispatch.getReleaseFences(mDevice, display, &count,
- outLayers->data(), outReleaseFences->data());
- if (err != HWC2_ERROR_NONE) {
- ALOGW("failed to get release fences");
- outLayers->clear();
- outReleaseFences->clear();
- return Error::NONE;
- }
-
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setLayerCursorPosition(Display display, Layer layer,
- int32_t x, int32_t y)
-{
- int32_t err = mDispatch.setCursorPosition(mDevice, display, layer, x, y);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setLayerBuffer(Display display, Layer layer,
- buffer_handle_t buffer, int32_t acquireFence)
-{
- int32_t err = mDispatch.setLayerBuffer(mDevice, display, layer,
- buffer, acquireFence);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setLayerSurfaceDamage(Display display, Layer layer,
- const std::vector<hwc_rect_t>& damage)
-{
- hwc_region region = { damage.size(), damage.data() };
- int32_t err = mDispatch.setLayerSurfaceDamage(mDevice, display, layer,
- region);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setLayerBlendMode(Display display, Layer layer, int32_t mode)
-{
- int32_t err = mDispatch.setLayerBlendMode(mDevice, display, layer, mode);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setLayerColor(Display display, Layer layer,
- IComposerClient::Color color)
-{
- hwc_color_t hwc_color{color.r, color.g, color.b, color.a};
- int32_t err = mDispatch.setLayerColor(mDevice, display, layer, hwc_color);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setLayerCompositionType(Display display, Layer layer,
- int32_t type)
-{
- int32_t err = mDispatch.setLayerCompositionType(mDevice, display, layer,
- type);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setLayerDataspace(Display display, Layer layer,
- int32_t dataspace)
-{
- int32_t err = mDispatch.setLayerDataspace(mDevice, display, layer,
- dataspace);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setLayerDisplayFrame(Display display, Layer layer,
- const hwc_rect_t& frame)
-{
- int32_t err = mDispatch.setLayerDisplayFrame(mDevice, display, layer,
- frame);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setLayerPlaneAlpha(Display display, Layer layer, float alpha)
-{
- int32_t err = mDispatch.setLayerPlaneAlpha(mDevice, display, layer,
- alpha);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setLayerSidebandStream(Display display, Layer layer,
- buffer_handle_t stream)
-{
- int32_t err = mDispatch.setLayerSidebandStream(mDevice, display, layer,
- stream);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setLayerSourceCrop(Display display, Layer layer,
- const hwc_frect_t& crop)
-{
- int32_t err = mDispatch.setLayerSourceCrop(mDevice, display, layer, crop);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setLayerTransform(Display display, Layer layer,
- int32_t transform)
-{
- int32_t err = mDispatch.setLayerTransform(mDevice, display, layer,
- transform);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setLayerVisibleRegion(Display display, Layer layer,
- const std::vector<hwc_rect_t>& visible)
-{
- hwc_region_t region = { visible.size(), visible.data() };
- int32_t err = mDispatch.setLayerVisibleRegion(mDevice, display, layer,
- region);
- return static_cast<Error>(err);
-}
-
-Error HwcHal::setLayerZOrder(Display display, Layer layer, uint32_t z)
-{
- int32_t err = mDispatch.setLayerZOrder(mDevice, display, layer, z);
- return static_cast<Error>(err);
-}
-
-IComposer* HIDL_FETCH_IComposer(const char*)
-{
- const hw_module_t* module = nullptr;
- int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &module);
- if (err) {
- ALOGI("falling back to FB HAL");
- err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
- }
- if (err) {
- ALOGE("failed to get hwcomposer or fb module");
- return nullptr;
- }
-
- return new HwcHal(module);
-}
-
-} // namespace implementation
-} // namespace V2_1
-} // namespace composer
-} // namespace graphics
-} // namespace hardware
-} // namespace android
diff --git a/graphics/composer/2.1/default/Hwc.h b/graphics/composer/2.1/default/Hwc.h
deleted file mode 100644
index e3f5ce6..0000000
--- a/graphics/composer/2.1/default/Hwc.h
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright 2016 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.
- */
-
-#ifndef ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_HWC_H
-#define ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_HWC_H
-
-#include <atomic>
-#include <condition_variable>
-#include <memory>
-#include <mutex>
-#include <unordered_set>
-#include <vector>
-
-#include <android/hardware/graphics/composer/2.1/IComposer.h>
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-#include "ComposerBase.h"
-
-namespace android {
- class HWC2On1Adapter;
- class HWC2OnFbAdapter;
-}
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_1 {
-namespace implementation {
-
-using android::hardware::graphics::common::V1_0::PixelFormat;
-using android::hardware::graphics::common::V1_0::Transform;
-using android::hardware::graphics::common::V1_0::Dataspace;
-using android::hardware::graphics::common::V1_0::ColorMode;
-using android::hardware::graphics::common::V1_0::ColorTransform;
-using android::hardware::graphics::common::V1_0::Hdr;
-
-class ComposerClient;
-
-class HwcHal : public IComposer, public ComposerBase {
-public:
- HwcHal(const hw_module_t* module);
- virtual ~HwcHal();
-
- // IComposer interface
- Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
- Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
- Return<void> createClient(createClient_cb hidl_cb) override;
-
- // ComposerBase interface
- bool hasCapability(hwc2_capability_t capability) override;
- void removeClient() override;
- void enableCallback(bool enable) override;
- uint32_t getMaxVirtualDisplayCount() override;
- Error createVirtualDisplay(uint32_t width, uint32_t height,
- PixelFormat* format, Display* outDisplay) override;
- Error destroyVirtualDisplay(Display display) override;
-
- Error createLayer(Display display, Layer* outLayer) override;
- Error destroyLayer(Display display, Layer layer) override;
-
- Error getActiveConfig(Display display, Config* outConfig) override;
- Error getClientTargetSupport(Display display,
- uint32_t width, uint32_t height,
- PixelFormat format, Dataspace dataspace) override;
- Error getColorModes(Display display,
- hidl_vec<ColorMode>* outModes) override;
- Error getDisplayAttribute(Display display, Config config,
- IComposerClient::Attribute attribute, int32_t* outValue) override;
- Error getDisplayConfigs(Display display,
- hidl_vec<Config>* outConfigs) override;
- Error getDisplayName(Display display, hidl_string* outName) override;
- Error getDisplayType(Display display,
- IComposerClient::DisplayType* outType) override;
- Error getDozeSupport(Display display, bool* outSupport) override;
- Error getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes,
- float* outMaxLuminance, float* outMaxAverageLuminance,
- float* outMinLuminance) override;
-
- Error setActiveConfig(Display display, Config config) override;
- Error setColorMode(Display display, ColorMode mode) override;
- Error setPowerMode(Display display,
- IComposerClient::PowerMode mode) override;
- Error setVsyncEnabled(Display display,
- IComposerClient::Vsync enabled) override;
-
- Error setColorTransform(Display display, const float* matrix,
- int32_t hint) override;
- Error setClientTarget(Display display, buffer_handle_t target,
- int32_t acquireFence, int32_t dataspace,
- const std::vector<hwc_rect_t>& damage) override;
- Error setOutputBuffer(Display display, buffer_handle_t buffer,
- int32_t releaseFence) override;
- Error validateDisplay(Display display,
- std::vector<Layer>* outChangedLayers,
- std::vector<IComposerClient::Composition>* outCompositionTypes,
- uint32_t* outDisplayRequestMask,
- std::vector<Layer>* outRequestedLayers,
- std::vector<uint32_t>* outRequestMasks) override;
- Error acceptDisplayChanges(Display display) override;
- Error presentDisplay(Display display, int32_t* outPresentFence,
- std::vector<Layer>* outLayers,
- std::vector<int32_t>* outReleaseFences) override;
-
- Error setLayerCursorPosition(Display display, Layer layer,
- int32_t x, int32_t y) override;
- Error setLayerBuffer(Display display, Layer layer,
- buffer_handle_t buffer, int32_t acquireFence) override;
- Error setLayerSurfaceDamage(Display display, Layer layer,
- const std::vector<hwc_rect_t>& damage) override;
- Error setLayerBlendMode(Display display, Layer layer,
- int32_t mode) override;
- Error setLayerColor(Display display, Layer layer,
- IComposerClient::Color color) override;
- Error setLayerCompositionType(Display display, Layer layer,
- int32_t type) override;
- Error setLayerDataspace(Display display, Layer layer,
- int32_t dataspace) override;
- Error setLayerDisplayFrame(Display display, Layer layer,
- const hwc_rect_t& frame) override;
- Error setLayerPlaneAlpha(Display display, Layer layer,
- float alpha) override;
- Error setLayerSidebandStream(Display display, Layer layer,
- buffer_handle_t stream) override;
- Error setLayerSourceCrop(Display display, Layer layer,
- const hwc_frect_t& crop) override;
- Error setLayerTransform(Display display, Layer layer,
- int32_t transform) override;
- Error setLayerVisibleRegion(Display display, Layer layer,
- const std::vector<hwc_rect_t>& visible) override;
- Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
-
-private:
- uint32_t initWithHwc(const hw_module_t* module);
- uint32_t initWithFb(const hw_module_t* module);
-
- void initCapabilities();
-
- template<typename T>
- void initDispatch(hwc2_function_descriptor_t desc, T* outPfn);
- void initDispatch();
-
- sp<ComposerClient> getClient();
-
- static void hotplugHook(hwc2_callback_data_t callbackData,
- hwc2_display_t display, int32_t connected);
- static void refreshHook(hwc2_callback_data_t callbackData,
- hwc2_display_t display);
- static void vsyncHook(hwc2_callback_data_t callbackData,
- hwc2_display_t display, int64_t timestamp);
-
- hwc2_device_t* mDevice;
-
- std::unordered_set<hwc2_capability_t> mCapabilities;
-
- struct {
- HWC2_PFN_ACCEPT_DISPLAY_CHANGES acceptDisplayChanges;
- HWC2_PFN_CREATE_LAYER createLayer;
- HWC2_PFN_CREATE_VIRTUAL_DISPLAY createVirtualDisplay;
- HWC2_PFN_DESTROY_LAYER destroyLayer;
- HWC2_PFN_DESTROY_VIRTUAL_DISPLAY destroyVirtualDisplay;
- HWC2_PFN_DUMP dump;
- HWC2_PFN_GET_ACTIVE_CONFIG getActiveConfig;
- HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES getChangedCompositionTypes;
- HWC2_PFN_GET_CLIENT_TARGET_SUPPORT getClientTargetSupport;
- HWC2_PFN_GET_COLOR_MODES getColorModes;
- HWC2_PFN_GET_DISPLAY_ATTRIBUTE getDisplayAttribute;
- HWC2_PFN_GET_DISPLAY_CONFIGS getDisplayConfigs;
- HWC2_PFN_GET_DISPLAY_NAME getDisplayName;
- HWC2_PFN_GET_DISPLAY_REQUESTS getDisplayRequests;
- HWC2_PFN_GET_DISPLAY_TYPE getDisplayType;
- HWC2_PFN_GET_DOZE_SUPPORT getDozeSupport;
- HWC2_PFN_GET_HDR_CAPABILITIES getHdrCapabilities;
- HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT getMaxVirtualDisplayCount;
- HWC2_PFN_GET_RELEASE_FENCES getReleaseFences;
- HWC2_PFN_PRESENT_DISPLAY presentDisplay;
- HWC2_PFN_REGISTER_CALLBACK registerCallback;
- HWC2_PFN_SET_ACTIVE_CONFIG setActiveConfig;
- HWC2_PFN_SET_CLIENT_TARGET setClientTarget;
- HWC2_PFN_SET_COLOR_MODE setColorMode;
- HWC2_PFN_SET_COLOR_TRANSFORM setColorTransform;
- HWC2_PFN_SET_CURSOR_POSITION setCursorPosition;
- HWC2_PFN_SET_LAYER_BLEND_MODE setLayerBlendMode;
- HWC2_PFN_SET_LAYER_BUFFER setLayerBuffer;
- HWC2_PFN_SET_LAYER_COLOR setLayerColor;
- HWC2_PFN_SET_LAYER_COMPOSITION_TYPE setLayerCompositionType;
- HWC2_PFN_SET_LAYER_DATASPACE setLayerDataspace;
- HWC2_PFN_SET_LAYER_DISPLAY_FRAME setLayerDisplayFrame;
- HWC2_PFN_SET_LAYER_PLANE_ALPHA setLayerPlaneAlpha;
- HWC2_PFN_SET_LAYER_SIDEBAND_STREAM setLayerSidebandStream;
- HWC2_PFN_SET_LAYER_SOURCE_CROP setLayerSourceCrop;
- HWC2_PFN_SET_LAYER_SURFACE_DAMAGE setLayerSurfaceDamage;
- HWC2_PFN_SET_LAYER_TRANSFORM setLayerTransform;
- HWC2_PFN_SET_LAYER_VISIBLE_REGION setLayerVisibleRegion;
- HWC2_PFN_SET_LAYER_Z_ORDER setLayerZOrder;
- HWC2_PFN_SET_OUTPUT_BUFFER setOutputBuffer;
- HWC2_PFN_SET_POWER_MODE setPowerMode;
- HWC2_PFN_SET_VSYNC_ENABLED setVsyncEnabled;
- HWC2_PFN_VALIDATE_DISPLAY validateDisplay;
- } mDispatch;
-
- std::mutex mClientMutex;
- std::condition_variable mClientDestroyedWait;
- wp<ComposerClient> mClient;
-
- std::atomic<bool> mMustValidateDisplay;
-
- // If the HWC implementation version is < 2.0, use an adapter to interface
- // between HWC 2.0 <-> HWC 1.X.
- std::unique_ptr<HWC2On1Adapter> mAdapter;
-
- // If there is no HWC implementation, use an adapter to interface between
- // HWC 2.0 <-> FB HAL.
- std::unique_ptr<HWC2OnFbAdapter> mFbAdapter;
-};
-
-extern "C" IComposer* HIDL_FETCH_IComposer(const char* name);
-
-} // namespace implementation
-} // namespace V2_1
-} // namespace composer
-} // namespace graphics
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_HWC_H
diff --git a/graphics/composer/2.1/default/passthrough.cpp b/graphics/composer/2.1/default/passthrough.cpp
new file mode 100644
index 0000000..ef7ed7c
--- /dev/null
+++ b/graphics/composer/2.1/default/passthrough.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#include <android/hardware/graphics/composer/2.1/IComposer.h>
+#include <composer-passthrough/2.1/HwcLoader.h>
+
+using android::hardware::graphics::composer::V2_1::IComposer;
+using android::hardware::graphics::composer::V2_1::passthrough::HwcLoader;
+
+extern "C" IComposer* HIDL_FETCH_IComposer(const char* /* name */) {
+ return HwcLoader::load();
+}
diff --git a/graphics/composer/2.1/utils/command-buffer/Android.bp b/graphics/composer/2.1/utils/command-buffer/Android.bp
index e8d41c2..140d9bb 100644
--- a/graphics/composer/2.1/utils/command-buffer/Android.bp
+++ b/graphics/composer/2.1/utils/command-buffer/Android.bp
@@ -2,6 +2,15 @@
name: "android.hardware.graphics.composer@2.1-command-buffer",
defaults: ["hidl_defaults"],
vendor_available: true,
- shared_libs: ["android.hardware.graphics.composer@2.1"],
+ shared_libs: [
+ "android.hardware.graphics.composer@2.1",
+ "libfmq",
+ "libsync",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.graphics.composer@2.1",
+ "libfmq",
+ "libsync",
+ ],
export_include_dirs: ["include"],
}
diff --git a/graphics/composer/2.1/utils/hal/Android.bp b/graphics/composer/2.1/utils/hal/Android.bp
new file mode 100644
index 0000000..f24e768
--- /dev/null
+++ b/graphics/composer/2.1/utils/hal/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2018 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.
+
+cc_library_headers {
+ name: "android.hardware.graphics.composer@2.1-hal",
+ defaults: ["hidl_defaults"],
+ vendor_available: true,
+ shared_libs: [
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.mapper@2.0",
+ "libhardware", // TODO remove hwcomposer2.h dependency
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.mapper@2.0",
+ "libhardware",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ ],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h
new file mode 100644
index 0000000..581dc96
--- /dev/null
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "Composer.h included without LOG_TAG"
+#endif
+
+#include <array>
+#include <chrono>
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#include <android/hardware/graphics/composer/2.1/IComposer.h>
+#include <android/hardware/graphics/composer/2.1/IComposerClient.h>
+#include <composer-hal/2.1/ComposerClient.h>
+#include <composer-hal/2.1/ComposerHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace hal {
+
+namespace detail {
+
+// ComposerImpl implements V2_*::IComposer on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerImpl : public Interface {
+ public:
+ static std::unique_ptr<ComposerImpl> create(std::unique_ptr<Hal> hal) {
+ return std::make_unique<ComposerImpl>(std::move(hal));
+ }
+
+ ComposerImpl(std::unique_ptr<Hal> hal) : mHal(std::move(hal)) {}
+
+ // IComposer 2.1 interface
+
+ Return<void> getCapabilities(IComposer::getCapabilities_cb hidl_cb) override {
+ const std::array<IComposer::Capability, 3> all_caps = {{
+ IComposer::Capability::SIDEBAND_STREAM,
+ IComposer::Capability::SKIP_CLIENT_COLOR_TRANSFORM,
+ IComposer::Capability::PRESENT_FENCE_IS_NOT_RELIABLE,
+ }};
+
+ std::vector<IComposer::Capability> caps;
+ for (auto cap : all_caps) {
+ if (mHal->hasCapability(static_cast<hwc2_capability_t>(cap))) {
+ caps.push_back(cap);
+ }
+ }
+
+ hidl_vec<IComposer::Capability> caps_reply;
+ caps_reply.setToExternal(caps.data(), caps.size());
+ hidl_cb(caps_reply);
+ return Void();
+ }
+
+ Return<void> dumpDebugInfo(IComposer::dumpDebugInfo_cb hidl_cb) override {
+ hidl_cb(mHal->dumpDebugInfo());
+ return Void();
+ }
+
+ Return<void> createClient(IComposer::createClient_cb hidl_cb) override {
+ std::unique_lock<std::mutex> lock(mClientMutex);
+ if (!waitForClientDestroyedLocked(lock)) {
+ hidl_cb(Error::NO_RESOURCES, nullptr);
+ return Void();
+ }
+
+ sp<IComposerClient> client = createClient();
+ if (!client) {
+ hidl_cb(Error::NO_RESOURCES, nullptr);
+ return Void();
+ }
+
+ mClient = client;
+ hidl_cb(Error::NONE, client);
+ return Void();
+ }
+
+ protected:
+ bool waitForClientDestroyedLocked(std::unique_lock<std::mutex>& lock) {
+ if (mClient != nullptr) {
+ using namespace std::chrono_literals;
+
+ // In surface flinger we delete a composer client on one thread and
+ // then create a new client on another thread. Although surface
+ // flinger ensures the calls are made in that sequence (destroy and
+ // then create), sometimes the calls land in the composer service
+ // inverted (create and then destroy). Wait for a brief period to
+ // see if the existing client is destroyed.
+ ALOGD("waiting for previous client to be destroyed");
+ mClientDestroyedCondition.wait_for(
+ lock, 1s, [this]() -> bool { return mClient.promote() == nullptr; });
+ if (mClient.promote() != nullptr) {
+ ALOGD("previous client was not destroyed");
+ } else {
+ mClient.clear();
+ }
+ }
+
+ return mClient == nullptr;
+ }
+
+ void onClientDestroyed() {
+ std::lock_guard<std::mutex> lock(mClientMutex);
+ mClient.clear();
+ mClientDestroyedCondition.notify_all();
+ }
+
+ virtual IComposerClient* createClient() {
+ auto client = ComposerClient::create(mHal.get());
+ if (!client) {
+ return nullptr;
+ }
+
+ auto clientDestroyed = [this]() { onClientDestroyed(); };
+ client->setOnClientDestroyed(clientDestroyed);
+
+ return client.release();
+ }
+
+ const std::unique_ptr<Hal> mHal;
+
+ std::mutex mClientMutex;
+ wp<IComposerClient> mClient;
+ std::condition_variable mClientDestroyedCondition;
+};
+
+} // namespace detail
+
+using Composer = detail::ComposerImpl<IComposer, ComposerHal>;
+
+} // namespace hal
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
new file mode 100644
index 0000000..86525b8
--- /dev/null
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
@@ -0,0 +1,396 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerClient.h included without LOG_TAG"
+#endif
+
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#include <android/hardware/graphics/composer/2.1/IComposerClient.h>
+#include <composer-hal/2.1/ComposerCommandEngine.h>
+#include <composer-hal/2.1/ComposerHal.h>
+#include <composer-hal/2.1/ComposerResources.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace hal {
+
+namespace detail {
+
+// ComposerClientImpl implements V2_*::IComposerClient on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerClientImpl : public Interface {
+ public:
+ static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
+ auto client = std::make_unique<ComposerClientImpl>(hal);
+ return client->init() ? std::move(client) : nullptr;
+ }
+
+ ComposerClientImpl(Hal* hal) : mHal(hal) {}
+
+ virtual ~ComposerClientImpl() {
+ // not initialized
+ if (!mCommandEngine) {
+ return;
+ }
+
+ ALOGD("destroying composer client");
+
+ mHal->unregisterEventCallback();
+ destroyResources();
+ if (mOnClientDestroyed) {
+ mOnClientDestroyed();
+ }
+
+ ALOGD("removed composer client");
+ }
+
+ bool init() {
+ mResources = createResources();
+ if (!mResources) {
+ ALOGE("failed to create composer resources");
+ return false;
+ }
+
+ mCommandEngine = createCommandEngine();
+
+ return true;
+ }
+
+ void setOnClientDestroyed(std::function<void()> onClientDestroyed) {
+ mOnClientDestroyed = onClientDestroyed;
+ }
+
+ // IComposerClient 2.1 interface
+
+ class HalEventCallback : public Hal::EventCallback {
+ public:
+ HalEventCallback(const sp<IComposerCallback> callback, ComposerResources* resources)
+ : mCallback(callback), mResources(resources) {}
+
+ void onHotplug(Display display, IComposerCallback::Connection connected) {
+ if (connected == IComposerCallback::Connection::CONNECTED) {
+ mResources->addPhysicalDisplay(display);
+ } else if (connected == IComposerCallback::Connection::DISCONNECTED) {
+ mResources->removeDisplay(display);
+ }
+
+ auto ret = mCallback->onHotplug(display, connected);
+ ALOGE_IF(!ret.isOk(), "failed to send onHotplug: %s", ret.description().c_str());
+ }
+
+ void onRefresh(Display display) {
+ auto ret = mCallback->onRefresh(display);
+ ALOGE_IF(!ret.isOk(), "failed to send onRefresh: %s", ret.description().c_str());
+ }
+
+ void onVsync(Display display, int64_t timestamp) {
+ auto ret = mCallback->onVsync(display, timestamp);
+ ALOGE_IF(!ret.isOk(), "failed to send onVsync: %s", ret.description().c_str());
+ }
+
+ protected:
+ const sp<IComposerCallback> mCallback;
+ ComposerResources* const mResources;
+ };
+
+ Return<void> registerCallback(const sp<IComposerCallback>& callback) override {
+ // no locking as we require this function to be called only once
+ mHalEventCallback = std::make_unique<HalEventCallback>(callback, mResources.get());
+ mHal->registerEventCallback(mHalEventCallback.get());
+ return Void();
+ }
+
+ Return<uint32_t> getMaxVirtualDisplayCount() override {
+ return mHal->getMaxVirtualDisplayCount();
+ }
+
+ Return<void> createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat formatHint,
+ uint32_t outputBufferSlotCount,
+ IComposerClient::createVirtualDisplay_cb hidl_cb) override {
+ Display display = 0;
+ Error err = mHal->createVirtualDisplay(width, height, &formatHint, &display);
+ if (err == Error::NONE) {
+ mResources->addVirtualDisplay(display, outputBufferSlotCount);
+ }
+
+ hidl_cb(err, display, formatHint);
+ return Void();
+ }
+
+ Return<Error> destroyVirtualDisplay(Display display) override {
+ Error err = mHal->destroyVirtualDisplay(display);
+ if (err == Error::NONE) {
+ mResources->removeDisplay(display);
+ }
+
+ return err;
+ }
+
+ Return<void> createLayer(Display display, uint32_t bufferSlotCount,
+ IComposerClient::createLayer_cb hidl_cb) override {
+ Layer layer = 0;
+ Error err = mHal->createLayer(display, &layer);
+ if (err == Error::NONE) {
+ err = mResources->addLayer(display, layer, bufferSlotCount);
+ if (err != Error::NONE) {
+ // The display entry may have already been removed by onHotplug.
+ // Note: We do not destroy the layer on this error as the hotplug
+ // disconnect invalidates the display id. The implementation should
+ // ensure all layers for the display are destroyed.
+ layer = 0;
+ }
+ }
+
+ hidl_cb(err, layer);
+ return Void();
+ }
+
+ Return<Error> destroyLayer(Display display, Layer layer) override {
+ Error err = mHal->destroyLayer(display, layer);
+ if (err == Error::NONE) {
+ mResources->removeLayer(display, layer);
+ }
+
+ return err;
+ }
+
+ Return<void> getActiveConfig(Display display,
+ IComposerClient::getActiveConfig_cb hidl_cb) override {
+ Config config = 0;
+ Error err = mHal->getActiveConfig(display, &config);
+ hidl_cb(err, config);
+ return Void();
+ }
+
+ Return<Error> getClientTargetSupport(Display display, uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace) override {
+ Error err = mHal->getClientTargetSupport(display, width, height, format, dataspace);
+ return err;
+ }
+
+ Return<void> getColorModes(Display display,
+ IComposerClient::getColorModes_cb hidl_cb) override {
+ hidl_vec<ColorMode> modes;
+ Error err = mHal->getColorModes(display, &modes);
+ hidl_cb(err, modes);
+ return Void();
+ }
+
+ Return<void> getDisplayAttribute(Display display, Config config,
+ IComposerClient::Attribute attribute,
+ IComposerClient::getDisplayAttribute_cb hidl_cb) override {
+ int32_t value = 0;
+ Error err = mHal->getDisplayAttribute(display, config, attribute, &value);
+ hidl_cb(err, value);
+ return Void();
+ }
+
+ Return<void> getDisplayConfigs(Display display,
+ IComposerClient::getDisplayConfigs_cb hidl_cb) override {
+ hidl_vec<Config> configs;
+ Error err = mHal->getDisplayConfigs(display, &configs);
+ hidl_cb(err, configs);
+ return Void();
+ }
+
+ Return<void> getDisplayName(Display display,
+ IComposerClient::getDisplayName_cb hidl_cb) override {
+ hidl_string name;
+ Error err = mHal->getDisplayName(display, &name);
+ hidl_cb(err, name);
+ return Void();
+ }
+
+ Return<void> getDisplayType(Display display,
+ IComposerClient::getDisplayType_cb hidl_cb) override {
+ IComposerClient::DisplayType type = IComposerClient::DisplayType::INVALID;
+ Error err = mHal->getDisplayType(display, &type);
+ hidl_cb(err, type);
+ return Void();
+ }
+
+ Return<void> getDozeSupport(Display display,
+ IComposerClient::getDozeSupport_cb hidl_cb) override {
+ bool support = false;
+ Error err = mHal->getDozeSupport(display, &support);
+ hidl_cb(err, support);
+ return Void();
+ }
+
+ Return<void> getHdrCapabilities(Display display,
+ IComposerClient::getHdrCapabilities_cb hidl_cb) override {
+ hidl_vec<Hdr> types;
+ float max_lumi = 0.0f;
+ float max_avg_lumi = 0.0f;
+ float min_lumi = 0.0f;
+ Error err = mHal->getHdrCapabilities(display, &types, &max_lumi, &max_avg_lumi, &min_lumi);
+ hidl_cb(err, types, max_lumi, max_avg_lumi, min_lumi);
+ return Void();
+ }
+
+ Return<Error> setActiveConfig(Display display, Config config) override {
+ Error err = mHal->setActiveConfig(display, config);
+ return err;
+ }
+
+ Return<Error> setColorMode(Display display, ColorMode mode) override {
+ Error err = mHal->setColorMode(display, mode);
+ return err;
+ }
+
+ Return<Error> setPowerMode(Display display, IComposerClient::PowerMode mode) override {
+ Error err = mHal->setPowerMode(display, mode);
+ return err;
+ }
+
+ Return<Error> setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override {
+ Error err = mHal->setVsyncEnabled(display, enabled);
+ return err;
+ }
+
+ Return<Error> setClientTargetSlotCount(Display display,
+ uint32_t clientTargetSlotCount) override {
+ return mResources->setDisplayClientTargetCacheSize(display, clientTargetSlotCount);
+ }
+
+ Return<Error> setInputCommandQueue(const MQDescriptorSync<uint32_t>& descriptor) override {
+ std::lock_guard<std::mutex> lock(mCommandEngineMutex);
+ return mCommandEngine->setInputMQDescriptor(descriptor) ? Error::NONE : Error::NO_RESOURCES;
+ }
+
+ Return<void> getOutputCommandQueue(IComposerClient::getOutputCommandQueue_cb hidl_cb) override {
+ // no locking as we require this function to be called inside
+ // executeCommands_cb
+ auto outDescriptor = mCommandEngine->getOutputMQDescriptor();
+ if (outDescriptor) {
+ hidl_cb(Error::NONE, *outDescriptor);
+ } else {
+ hidl_cb(Error::NO_RESOURCES, CommandQueueType::Descriptor());
+ }
+
+ return Void();
+ }
+
+ Return<void> executeCommands(uint32_t inLength, const hidl_vec<hidl_handle>& inHandles,
+ IComposerClient::executeCommands_cb hidl_cb) override {
+ std::lock_guard<std::mutex> lock(mCommandEngineMutex);
+ bool outChanged = false;
+ uint32_t outLength = 0;
+ hidl_vec<hidl_handle> outHandles;
+ Error error =
+ mCommandEngine->execute(inLength, inHandles, &outChanged, &outLength, &outHandles);
+
+ hidl_cb(error, outChanged, outLength, outHandles);
+
+ mCommandEngine->reset();
+
+ return Void();
+ }
+
+ protected:
+ virtual std::unique_ptr<ComposerResources> createResources() {
+ return ComposerResources::create();
+ }
+
+ virtual std::unique_ptr<ComposerCommandEngine> createCommandEngine() {
+ return std::make_unique<ComposerCommandEngine>(mHal, mResources.get());
+ }
+
+ void destroyResources() {
+ // We want to call hwc2_close here (and move hwc2_open to the
+ // constructor), with the assumption that hwc2_close would
+ //
+ // - clean up all resources owned by the client
+ // - make sure all displays are blank (since there is no layer)
+ //
+ // But since SF used to crash at this point, different hwcomposer2
+ // implementations behave differently on hwc2_close. Our only portable
+ // choice really is to abort(). But that is not an option anymore
+ // because we might also have VTS or VR as clients that can come and go.
+ //
+ // Below we manually clean all resources (layers and virtual
+ // displays), and perform a presentDisplay afterwards.
+ mResources->clear([this](Display display, bool isVirtual, const std::vector<Layer> layers) {
+ ALOGW("destroying client resources for display %" PRIu64, display);
+
+ for (auto layer : layers) {
+ mHal->destroyLayer(display, layer);
+ }
+
+ if (isVirtual) {
+ mHal->destroyVirtualDisplay(display);
+ } else {
+ ALOGW("performing a final presentDisplay");
+
+ std::vector<Layer> changedLayers;
+ std::vector<IComposerClient::Composition> compositionTypes;
+ uint32_t displayRequestMask = 0;
+ std::vector<Layer> requestedLayers;
+ std::vector<uint32_t> requestMasks;
+ mHal->validateDisplay(display, &changedLayers, &compositionTypes,
+ &displayRequestMask, &requestedLayers, &requestMasks);
+
+ mHal->acceptDisplayChanges(display);
+
+ int32_t presentFence = -1;
+ std::vector<Layer> releasedLayers;
+ std::vector<int32_t> releaseFences;
+ mHal->presentDisplay(display, &presentFence, &releasedLayers, &releaseFences);
+ if (presentFence >= 0) {
+ close(presentFence);
+ }
+ for (auto fence : releaseFences) {
+ if (fence >= 0) {
+ close(fence);
+ }
+ }
+ }
+ });
+
+ mResources.reset();
+ }
+
+ Hal* const mHal;
+
+ std::unique_ptr<ComposerResources> mResources;
+
+ std::mutex mCommandEngineMutex;
+ std::unique_ptr<ComposerCommandEngine> mCommandEngine;
+
+ std::function<void()> mOnClientDestroyed;
+ std::unique_ptr<HalEventCallback> mHalEventCallback;
+};
+
+} // namespace detail
+
+using ComposerClient = detail::ComposerClientImpl<IComposerClient, ComposerHal>;
+
+} // namespace hal
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
new file mode 100644
index 0000000..36aa64e
--- /dev/null
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
@@ -0,0 +1,594 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerCommandEngine.h included without LOG_TAG"
+#endif
+
+#include <vector>
+
+#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
+#include <composer-hal/2.1/ComposerHal.h>
+#include <composer-hal/2.1/ComposerResources.h>
+// TODO remove hwcomposer_defs.h dependency
+#include <hardware/hwcomposer_defs.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace hal {
+
+// TODO own a CommandReaderBase rather than subclassing
+class ComposerCommandEngine : protected CommandReaderBase {
+ public:
+ ComposerCommandEngine(ComposerHal* hal, ComposerResources* resources)
+ : mHal(hal), mResources(resources) {}
+
+ virtual ~ComposerCommandEngine() = default;
+
+ bool setInputMQDescriptor(const MQDescriptorSync<uint32_t>& descriptor) {
+ return setMQDescriptor(descriptor);
+ }
+
+ Error execute(uint32_t inLength, const hidl_vec<hidl_handle>& inHandles, bool* outQueueChanged,
+ uint32_t* outCommandLength, hidl_vec<hidl_handle>* outCommandHandles) {
+ if (!readQueue(inLength, inHandles)) {
+ return Error::BAD_PARAMETER;
+ }
+
+ IComposerClient::Command command;
+ uint16_t length = 0;
+ while (!isEmpty()) {
+ if (!beginCommand(&command, &length)) {
+ break;
+ }
+
+ bool parsed = executeCommand(command, length);
+ endCommand();
+
+ if (!parsed) {
+ ALOGE("failed to parse command 0x%x, length %" PRIu16, command, length);
+ break;
+ }
+ }
+
+ if (!isEmpty()) {
+ return Error::BAD_PARAMETER;
+ }
+
+ return mWriter.writeQueue(outQueueChanged, outCommandLength, outCommandHandles)
+ ? Error::NONE
+ : Error::NO_RESOURCES;
+ }
+
+ const MQDescriptorSync<uint32_t>* getOutputMQDescriptor() { return mWriter.getMQDescriptor(); }
+
+ void reset() {
+ CommandReaderBase::reset();
+ mWriter.reset();
+ }
+
+ protected:
+ virtual bool executeCommand(IComposerClient::Command command, uint16_t length) {
+ switch (command) {
+ case IComposerClient::Command::SELECT_DISPLAY:
+ return executeSelectDisplay(length);
+ case IComposerClient::Command::SELECT_LAYER:
+ return executeSelectLayer(length);
+ case IComposerClient::Command::SET_COLOR_TRANSFORM:
+ return executeSetColorTransform(length);
+ case IComposerClient::Command::SET_CLIENT_TARGET:
+ return executeSetClientTarget(length);
+ case IComposerClient::Command::SET_OUTPUT_BUFFER:
+ return executeSetOutputBuffer(length);
+ case IComposerClient::Command::VALIDATE_DISPLAY:
+ return executeValidateDisplay(length);
+ case IComposerClient::Command::PRESENT_OR_VALIDATE_DISPLAY:
+ return executePresentOrValidateDisplay(length);
+ case IComposerClient::Command::ACCEPT_DISPLAY_CHANGES:
+ return executeAcceptDisplayChanges(length);
+ case IComposerClient::Command::PRESENT_DISPLAY:
+ return executePresentDisplay(length);
+ case IComposerClient::Command::SET_LAYER_CURSOR_POSITION:
+ return executeSetLayerCursorPosition(length);
+ case IComposerClient::Command::SET_LAYER_BUFFER:
+ return executeSetLayerBuffer(length);
+ case IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE:
+ return executeSetLayerSurfaceDamage(length);
+ case IComposerClient::Command::SET_LAYER_BLEND_MODE:
+ return executeSetLayerBlendMode(length);
+ case IComposerClient::Command::SET_LAYER_COLOR:
+ return executeSetLayerColor(length);
+ case IComposerClient::Command::SET_LAYER_COMPOSITION_TYPE:
+ return executeSetLayerCompositionType(length);
+ case IComposerClient::Command::SET_LAYER_DATASPACE:
+ return executeSetLayerDataspace(length);
+ case IComposerClient::Command::SET_LAYER_DISPLAY_FRAME:
+ return executeSetLayerDisplayFrame(length);
+ case IComposerClient::Command::SET_LAYER_PLANE_ALPHA:
+ return executeSetLayerPlaneAlpha(length);
+ case IComposerClient::Command::SET_LAYER_SIDEBAND_STREAM:
+ return executeSetLayerSidebandStream(length);
+ case IComposerClient::Command::SET_LAYER_SOURCE_CROP:
+ return executeSetLayerSourceCrop(length);
+ case IComposerClient::Command::SET_LAYER_TRANSFORM:
+ return executeSetLayerTransform(length);
+ case IComposerClient::Command::SET_LAYER_VISIBLE_REGION:
+ return executeSetLayerVisibleRegion(length);
+ case IComposerClient::Command::SET_LAYER_Z_ORDER:
+ return executeSetLayerZOrder(length);
+ default:
+ return false;
+ }
+ }
+
+ bool executeSelectDisplay(uint16_t length) {
+ if (length != CommandWriterBase::kSelectDisplayLength) {
+ return false;
+ }
+
+ mCurrentDisplay = read64();
+ mWriter.selectDisplay(mCurrentDisplay);
+
+ return true;
+ }
+
+ bool executeSelectLayer(uint16_t length) {
+ if (length != CommandWriterBase::kSelectLayerLength) {
+ return false;
+ }
+
+ mCurrentLayer = read64();
+
+ return true;
+ }
+
+ bool executeSetColorTransform(uint16_t length) {
+ if (length != CommandWriterBase::kSetColorTransformLength) {
+ return false;
+ }
+
+ float matrix[16];
+ for (int i = 0; i < 16; i++) {
+ matrix[i] = readFloat();
+ }
+ auto transform = readSigned();
+
+ auto err = mHal->setColorTransform(mCurrentDisplay, matrix, transform);
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeSetClientTarget(uint16_t length) {
+ // 4 parameters followed by N rectangles
+ if ((length - 4) % 4 != 0) {
+ return false;
+ }
+
+ bool useCache = false;
+ auto slot = read();
+ auto rawHandle = readHandle(&useCache);
+ auto fence = readFence();
+ auto dataspace = readSigned();
+ auto damage = readRegion((length - 4) / 4);
+ bool closeFence = true;
+
+ const native_handle_t* clientTarget;
+ ComposerResources::ReplacedBufferHandle replacedClientTarget;
+ auto err = mResources->getDisplayClientTarget(mCurrentDisplay, slot, useCache, rawHandle,
+ &clientTarget, &replacedClientTarget);
+ if (err == Error::NONE) {
+ err = mHal->setClientTarget(mCurrentDisplay, clientTarget, fence, dataspace, damage);
+ if (err == Error::NONE) {
+ closeFence = false;
+ }
+ }
+ if (closeFence) {
+ close(fence);
+ }
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeSetOutputBuffer(uint16_t length) {
+ if (length != CommandWriterBase::kSetOutputBufferLength) {
+ return false;
+ }
+
+ bool useCache = false;
+ auto slot = read();
+ auto rawhandle = readHandle(&useCache);
+ auto fence = readFence();
+ bool closeFence = true;
+
+ const native_handle_t* outputBuffer;
+ ComposerResources::ReplacedBufferHandle replacedOutputBuffer;
+ auto err = mResources->getDisplayOutputBuffer(mCurrentDisplay, slot, useCache, rawhandle,
+ &outputBuffer, &replacedOutputBuffer);
+ if (err == Error::NONE) {
+ err = mHal->setOutputBuffer(mCurrentDisplay, outputBuffer, fence);
+ if (err == Error::NONE) {
+ closeFence = false;
+ }
+ }
+ if (closeFence) {
+ close(fence);
+ }
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeValidateDisplay(uint16_t length) {
+ if (length != CommandWriterBase::kValidateDisplayLength) {
+ return false;
+ }
+
+ std::vector<Layer> changedLayers;
+ std::vector<IComposerClient::Composition> compositionTypes;
+ uint32_t displayRequestMask = 0x0;
+ std::vector<Layer> requestedLayers;
+ std::vector<uint32_t> requestMasks;
+
+ auto err = mHal->validateDisplay(mCurrentDisplay, &changedLayers, &compositionTypes,
+ &displayRequestMask, &requestedLayers, &requestMasks);
+ if (err == Error::NONE) {
+ mWriter.setChangedCompositionTypes(changedLayers, compositionTypes);
+ mWriter.setDisplayRequests(displayRequestMask, requestedLayers, requestMasks);
+ } else {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executePresentOrValidateDisplay(uint16_t length) {
+ if (length != CommandWriterBase::kPresentOrValidateDisplayLength) {
+ return false;
+ }
+
+ // First try to Present as is.
+ if (mHal->hasCapability(HWC2_CAPABILITY_SKIP_VALIDATE)) {
+ int presentFence = -1;
+ std::vector<Layer> layers;
+ std::vector<int> fences;
+ auto err = mHal->presentDisplay(mCurrentDisplay, &presentFence, &layers, &fences);
+ if (err == Error::NONE) {
+ mWriter.setPresentOrValidateResult(1);
+ mWriter.setPresentFence(presentFence);
+ mWriter.setReleaseFences(layers, fences);
+ return true;
+ }
+ }
+
+ // Present has failed. We need to fallback to validate
+ std::vector<Layer> changedLayers;
+ std::vector<IComposerClient::Composition> compositionTypes;
+ uint32_t displayRequestMask = 0x0;
+ std::vector<Layer> requestedLayers;
+ std::vector<uint32_t> requestMasks;
+
+ auto err = mHal->validateDisplay(mCurrentDisplay, &changedLayers, &compositionTypes,
+ &displayRequestMask, &requestedLayers, &requestMasks);
+ if (err == Error::NONE) {
+ mWriter.setPresentOrValidateResult(0);
+ mWriter.setChangedCompositionTypes(changedLayers, compositionTypes);
+ mWriter.setDisplayRequests(displayRequestMask, requestedLayers, requestMasks);
+ } else {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeAcceptDisplayChanges(uint16_t length) {
+ if (length != CommandWriterBase::kAcceptDisplayChangesLength) {
+ return false;
+ }
+
+ auto err = mHal->acceptDisplayChanges(mCurrentDisplay);
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executePresentDisplay(uint16_t length) {
+ if (length != CommandWriterBase::kPresentDisplayLength) {
+ return false;
+ }
+
+ int presentFence = -1;
+ std::vector<Layer> layers;
+ std::vector<int> fences;
+ auto err = mHal->presentDisplay(mCurrentDisplay, &presentFence, &layers, &fences);
+ if (err == Error::NONE) {
+ mWriter.setPresentFence(presentFence);
+ mWriter.setReleaseFences(layers, fences);
+ } else {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeSetLayerCursorPosition(uint16_t length) {
+ if (length != CommandWriterBase::kSetLayerCursorPositionLength) {
+ return false;
+ }
+
+ auto err = mHal->setLayerCursorPosition(mCurrentDisplay, mCurrentLayer, readSigned(),
+ readSigned());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeSetLayerBuffer(uint16_t length) {
+ if (length != CommandWriterBase::kSetLayerBufferLength) {
+ return false;
+ }
+
+ bool useCache = false;
+ auto slot = read();
+ auto rawHandle = readHandle(&useCache);
+ auto fence = readFence();
+ bool closeFence = true;
+
+ const native_handle_t* buffer;
+ ComposerResources::ReplacedBufferHandle replacedBuffer;
+ auto err = mResources->getLayerBuffer(mCurrentDisplay, mCurrentLayer, slot, useCache,
+ rawHandle, &buffer, &replacedBuffer);
+ if (err == Error::NONE) {
+ err = mHal->setLayerBuffer(mCurrentDisplay, mCurrentLayer, buffer, fence);
+ if (err == Error::NONE) {
+ closeFence = false;
+ }
+ }
+ if (closeFence) {
+ close(fence);
+ }
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeSetLayerSurfaceDamage(uint16_t length) {
+ // N rectangles
+ if (length % 4 != 0) {
+ return false;
+ }
+
+ auto damage = readRegion(length / 4);
+ auto err = mHal->setLayerSurfaceDamage(mCurrentDisplay, mCurrentLayer, damage);
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeSetLayerBlendMode(uint16_t length) {
+ if (length != CommandWriterBase::kSetLayerBlendModeLength) {
+ return false;
+ }
+
+ auto err = mHal->setLayerBlendMode(mCurrentDisplay, mCurrentLayer, readSigned());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeSetLayerColor(uint16_t length) {
+ if (length != CommandWriterBase::kSetLayerColorLength) {
+ return false;
+ }
+
+ auto err = mHal->setLayerColor(mCurrentDisplay, mCurrentLayer, readColor());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeSetLayerCompositionType(uint16_t length) {
+ if (length != CommandWriterBase::kSetLayerCompositionTypeLength) {
+ return false;
+ }
+
+ auto err = mHal->setLayerCompositionType(mCurrentDisplay, mCurrentLayer, readSigned());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeSetLayerDataspace(uint16_t length) {
+ if (length != CommandWriterBase::kSetLayerDataspaceLength) {
+ return false;
+ }
+
+ auto err = mHal->setLayerDataspace(mCurrentDisplay, mCurrentLayer, readSigned());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeSetLayerDisplayFrame(uint16_t length) {
+ if (length != CommandWriterBase::kSetLayerDisplayFrameLength) {
+ return false;
+ }
+
+ auto err = mHal->setLayerDisplayFrame(mCurrentDisplay, mCurrentLayer, readRect());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeSetLayerPlaneAlpha(uint16_t length) {
+ if (length != CommandWriterBase::kSetLayerPlaneAlphaLength) {
+ return false;
+ }
+
+ auto err = mHal->setLayerPlaneAlpha(mCurrentDisplay, mCurrentLayer, readFloat());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeSetLayerSidebandStream(uint16_t length) {
+ if (length != CommandWriterBase::kSetLayerSidebandStreamLength) {
+ return false;
+ }
+
+ auto rawHandle = readHandle();
+
+ const native_handle_t* stream;
+ ComposerResources::ReplacedStreamHandle replacedStream;
+ auto err = mResources->getLayerSidebandStream(mCurrentDisplay, mCurrentLayer, rawHandle,
+ &stream, &replacedStream);
+ if (err == Error::NONE) {
+ err = mHal->setLayerSidebandStream(mCurrentDisplay, mCurrentLayer, stream);
+ }
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeSetLayerSourceCrop(uint16_t length) {
+ if (length != CommandWriterBase::kSetLayerSourceCropLength) {
+ return false;
+ }
+
+ auto err = mHal->setLayerSourceCrop(mCurrentDisplay, mCurrentLayer, readFRect());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeSetLayerTransform(uint16_t length) {
+ if (length != CommandWriterBase::kSetLayerTransformLength) {
+ return false;
+ }
+
+ auto err = mHal->setLayerTransform(mCurrentDisplay, mCurrentLayer, readSigned());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeSetLayerVisibleRegion(uint16_t length) {
+ // N rectangles
+ if (length % 4 != 0) {
+ return false;
+ }
+
+ auto region = readRegion(length / 4);
+ auto err = mHal->setLayerVisibleRegion(mCurrentDisplay, mCurrentLayer, region);
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeSetLayerZOrder(uint16_t length) {
+ if (length != CommandWriterBase::kSetLayerZOrderLength) {
+ return false;
+ }
+
+ auto err = mHal->setLayerZOrder(mCurrentDisplay, mCurrentLayer, read());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ hwc_rect_t readRect() {
+ return hwc_rect_t{
+ readSigned(), readSigned(), readSigned(), readSigned(),
+ };
+ }
+
+ std::vector<hwc_rect_t> readRegion(size_t count) {
+ std::vector<hwc_rect_t> region;
+ region.reserve(count);
+ while (count > 0) {
+ region.emplace_back(readRect());
+ count--;
+ }
+
+ return region;
+ }
+
+ hwc_frect_t readFRect() {
+ return hwc_frect_t{
+ readFloat(), readFloat(), readFloat(), readFloat(),
+ };
+ }
+
+ ComposerHal* mHal;
+ ComposerResources* mResources;
+
+ // 64KiB minus a small space for metadata such as read/write pointers
+ static constexpr size_t kWriterInitialSize = 64 * 1024 / sizeof(uint32_t) - 16;
+ CommandWriterBase mWriter{kWriterInitialSize};
+
+ Display mCurrentDisplay = 0;
+ Layer mCurrentLayer = 0;
+};
+
+} // namespace hal
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerHal.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerHal.h
new file mode 100644
index 0000000..c9793fd
--- /dev/null
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerHal.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <android/hardware/graphics/composer/2.1/IComposer.h>
+#include <android/hardware/graphics/composer/2.1/IComposerClient.h>
+
+// TODO remove hwcomposer2.h dependency
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace hal {
+
+using common::V1_0::ColorMode;
+using common::V1_0::ColorTransform;
+using common::V1_0::Dataspace;
+using common::V1_0::Hdr;
+using common::V1_0::PixelFormat;
+using common::V1_0::Transform;
+
+class ComposerHal {
+ public:
+ virtual ~ComposerHal() = default;
+
+ virtual bool hasCapability(hwc2_capability_t capability) = 0;
+
+ // dump the debug information
+ virtual std::string dumpDebugInfo() = 0;
+
+ class EventCallback {
+ public:
+ virtual ~EventCallback() = default;
+ virtual void onHotplug(Display display, IComposerCallback::Connection connected) = 0;
+ virtual void onRefresh(Display display) = 0;
+ virtual void onVsync(Display display, int64_t timestamp) = 0;
+ };
+
+ // Register the event callback object. The event callback object is valid
+ // until it is unregistered. A hotplug event must be generated for each
+ // connected physical display, before or after this function returns.
+ virtual void registerEventCallback(EventCallback* callback) = 0;
+
+ // Unregister the event callback object. It must block if there is any
+ // callback in-flight.
+ virtual void unregisterEventCallback() = 0;
+
+ virtual uint32_t getMaxVirtualDisplayCount() = 0;
+ virtual Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
+ Display* outDisplay) = 0;
+ virtual Error destroyVirtualDisplay(Display display) = 0;
+ virtual Error createLayer(Display display, Layer* outLayer) = 0;
+ virtual Error destroyLayer(Display display, Layer layer) = 0;
+
+ virtual Error getActiveConfig(Display display, Config* outConfig) = 0;
+ virtual Error getClientTargetSupport(Display display, uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace) = 0;
+ virtual Error getColorModes(Display display, hidl_vec<ColorMode>* outModes) = 0;
+ virtual Error getDisplayAttribute(Display display, Config config,
+ IComposerClient::Attribute attribute, int32_t* outValue) = 0;
+ virtual Error getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) = 0;
+ virtual Error getDisplayName(Display display, hidl_string* outName) = 0;
+ virtual Error getDisplayType(Display display, IComposerClient::DisplayType* outType) = 0;
+ virtual Error getDozeSupport(Display display, bool* outSupport) = 0;
+ virtual Error getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes,
+ float* outMaxLuminance, float* outMaxAverageLuminance,
+ float* outMinLuminance) = 0;
+
+ virtual Error setActiveConfig(Display display, Config config) = 0;
+ virtual Error setColorMode(Display display, ColorMode mode) = 0;
+ virtual Error setPowerMode(Display display, IComposerClient::PowerMode mode) = 0;
+ virtual Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) = 0;
+
+ virtual Error setColorTransform(Display display, const float* matrix, int32_t hint) = 0;
+ virtual Error setClientTarget(Display display, buffer_handle_t target, int32_t acquireFence,
+ int32_t dataspace, const std::vector<hwc_rect_t>& damage) = 0;
+ virtual Error setOutputBuffer(Display display, buffer_handle_t buffer,
+ int32_t releaseFence) = 0;
+ virtual Error validateDisplay(Display display, std::vector<Layer>* outChangedLayers,
+ std::vector<IComposerClient::Composition>* outCompositionTypes,
+ uint32_t* outDisplayRequestMask,
+ std::vector<Layer>* outRequestedLayers,
+ std::vector<uint32_t>* outRequestMasks) = 0;
+ virtual Error acceptDisplayChanges(Display display) = 0;
+ virtual Error presentDisplay(Display display, int32_t* outPresentFence,
+ std::vector<Layer>* outLayers,
+ std::vector<int32_t>* outReleaseFences) = 0;
+
+ virtual Error setLayerCursorPosition(Display display, Layer layer, int32_t x, int32_t y) = 0;
+ virtual Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer,
+ int32_t acquireFence) = 0;
+ virtual Error setLayerSurfaceDamage(Display display, Layer layer,
+ const std::vector<hwc_rect_t>& damage) = 0;
+ virtual Error setLayerBlendMode(Display display, Layer layer, int32_t mode) = 0;
+ virtual Error setLayerColor(Display display, Layer layer, IComposerClient::Color color) = 0;
+ virtual Error setLayerCompositionType(Display display, Layer layer, int32_t type) = 0;
+ virtual Error setLayerDataspace(Display display, Layer layer, int32_t dataspace) = 0;
+ virtual Error setLayerDisplayFrame(Display display, Layer layer, const hwc_rect_t& frame) = 0;
+ virtual Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) = 0;
+ virtual Error setLayerSidebandStream(Display display, Layer layer, buffer_handle_t stream) = 0;
+ virtual Error setLayerSourceCrop(Display display, Layer layer, const hwc_frect_t& crop) = 0;
+ virtual Error setLayerTransform(Display display, Layer layer, int32_t transform) = 0;
+ virtual Error setLayerVisibleRegion(Display display, Layer layer,
+ const std::vector<hwc_rect_t>& visible) = 0;
+ virtual Error setLayerZOrder(Display display, Layer layer, uint32_t z) = 0;
+};
+
+} // namespace hal
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h
new file mode 100644
index 0000000..7bb3692
--- /dev/null
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h
@@ -0,0 +1,536 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerResources.h included without LOG_TAG"
+#endif
+
+#include <memory>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace hal {
+
+// wrapper for IMapper to import buffers and sideband streams
+class ComposerHandleImporter {
+ public:
+ bool init() {
+ mMapper = mapper::V2_0::IMapper::getService();
+ ALOGE_IF(!mMapper, "failed to get mapper service");
+ return mMapper != nullptr;
+ }
+
+ Error importBuffer(const native_handle_t* rawHandle, const native_handle_t** outBufferHandle) {
+ if (!rawHandle || (!rawHandle->numFds && !rawHandle->numInts)) {
+ *outBufferHandle = nullptr;
+ return Error::NONE;
+ }
+
+ mapper::V2_0::Error error;
+ const native_handle_t* bufferHandle;
+ mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
+ error = tmpError;
+ bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
+ });
+ if (error != mapper::V2_0::Error::NONE) {
+ return Error::NO_RESOURCES;
+ }
+
+ *outBufferHandle = bufferHandle;
+ return Error::NONE;
+ }
+
+ void freeBuffer(const native_handle_t* bufferHandle) {
+ if (bufferHandle) {
+ mMapper->freeBuffer(static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
+ }
+ }
+
+ Error importStream(const native_handle_t* rawHandle, const native_handle_t** outStreamHandle) {
+ const native_handle_t* streamHandle = nullptr;
+ if (rawHandle) {
+ streamHandle = native_handle_clone(rawHandle);
+ if (!streamHandle) {
+ return Error::NO_RESOURCES;
+ }
+ }
+
+ *outStreamHandle = streamHandle;
+ return Error::NONE;
+ }
+
+ void freeStream(const native_handle_t* streamHandle) {
+ if (streamHandle) {
+ native_handle_close(streamHandle);
+ native_handle_delete(const_cast<native_handle_t*>(streamHandle));
+ }
+ }
+
+ private:
+ sp<mapper::V2_0::IMapper> mMapper;
+};
+
+class ComposerHandleCache {
+ public:
+ enum class HandleType {
+ INVALID,
+ BUFFER,
+ STREAM,
+ };
+
+ ComposerHandleCache(ComposerHandleImporter& importer, HandleType type, uint32_t cacheSize)
+ : mImporter(importer), mHandleType(type), mHandles(cacheSize, nullptr) {}
+
+ // must be initialized later with initCache
+ ComposerHandleCache(ComposerHandleImporter& importer) : mImporter(importer) {}
+
+ ~ComposerHandleCache() {
+ switch (mHandleType) {
+ case HandleType::BUFFER:
+ for (auto handle : mHandles) {
+ mImporter.freeBuffer(handle);
+ }
+ break;
+ case HandleType::STREAM:
+ for (auto handle : mHandles) {
+ mImporter.freeStream(handle);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ ComposerHandleCache(const ComposerHandleCache&) = delete;
+ ComposerHandleCache& operator=(const ComposerHandleCache&) = delete;
+
+ bool initCache(HandleType type, uint32_t cacheSize) {
+ // already initialized
+ if (mHandleType != HandleType::INVALID) {
+ return false;
+ }
+
+ mHandleType = type;
+ mHandles.resize(cacheSize, nullptr);
+
+ return true;
+ }
+
+ Error lookupCache(uint32_t slot, const native_handle_t** outHandle) {
+ if (slot < mHandles.size()) {
+ *outHandle = mHandles[slot];
+ return Error::NONE;
+ } else {
+ return Error::BAD_PARAMETER;
+ }
+ }
+
+ Error updateCache(uint32_t slot, const native_handle_t* handle,
+ const native_handle** outReplacedHandle) {
+ if (slot < mHandles.size()) {
+ auto& cachedHandle = mHandles[slot];
+ *outReplacedHandle = cachedHandle;
+ cachedHandle = handle;
+ return Error::NONE;
+ } else {
+ return Error::BAD_PARAMETER;
+ }
+ }
+
+ // when fromCache is true, look up in the cache; otherwise, update the cache
+ Error getHandle(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+ const native_handle_t** outHandle, const native_handle** outReplacedHandle) {
+ if (fromCache) {
+ *outReplacedHandle = nullptr;
+ return lookupCache(slot, outHandle);
+ } else {
+ *outHandle = inHandle;
+ return updateCache(slot, inHandle, outReplacedHandle);
+ }
+ }
+
+ private:
+ ComposerHandleImporter& mImporter;
+ HandleType mHandleType = HandleType::INVALID;
+ std::vector<const native_handle_t*> mHandles;
+};
+
+// layer resource
+class ComposerLayerResource {
+ public:
+ ComposerLayerResource(ComposerHandleImporter& importer, uint32_t bufferCacheSize)
+ : mBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, bufferCacheSize),
+ mSidebandStreamCache(importer, ComposerHandleCache::HandleType::STREAM, 1) {}
+
+ Error getBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+ const native_handle_t** outHandle, const native_handle** outReplacedHandle) {
+ return mBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+ }
+
+ Error getSidebandStream(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle) {
+ return mSidebandStreamCache.getHandle(slot, fromCache, inHandle, outHandle,
+ outReplacedHandle);
+ }
+
+ protected:
+ ComposerHandleCache mBufferCache;
+ ComposerHandleCache mSidebandStreamCache;
+};
+
+// display resource
+class ComposerDisplayResource {
+ public:
+ enum class DisplayType {
+ PHYSICAL,
+ VIRTUAL,
+ };
+
+ ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
+ uint32_t outputBufferCacheSize)
+ : mType(type),
+ mClientTargetCache(importer),
+ mOutputBufferCache(importer, ComposerHandleCache::HandleType::BUFFER,
+ outputBufferCacheSize) {}
+
+ bool initClientTargetCache(uint32_t cacheSize) {
+ return mClientTargetCache.initCache(ComposerHandleCache::HandleType::BUFFER, cacheSize);
+ }
+
+ bool isVirtual() const { return mType == DisplayType::VIRTUAL; }
+
+ Error getClientTarget(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle) {
+ return mClientTargetCache.getHandle(slot, fromCache, inHandle, outHandle,
+ outReplacedHandle);
+ }
+
+ Error getOutputBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle) {
+ return mOutputBufferCache.getHandle(slot, fromCache, inHandle, outHandle,
+ outReplacedHandle);
+ }
+
+ bool addLayer(Layer layer, std::unique_ptr<ComposerLayerResource> layerResource) {
+ auto result = mLayerResources.emplace(layer, std::move(layerResource));
+ return result.second;
+ }
+
+ bool removeLayer(Layer layer) { return mLayerResources.erase(layer) > 0; }
+
+ ComposerLayerResource* findLayerResource(Layer layer) {
+ auto layerIter = mLayerResources.find(layer);
+ if (layerIter == mLayerResources.end()) {
+ return nullptr;
+ }
+
+ return layerIter->second.get();
+ }
+
+ std::vector<Layer> getLayers() const {
+ std::vector<Layer> layers;
+ layers.reserve(mLayerResources.size());
+ for (const auto& layerKey : mLayerResources) {
+ layers.push_back(layerKey.first);
+ }
+ return layers;
+ }
+
+ protected:
+ const DisplayType mType;
+ ComposerHandleCache mClientTargetCache;
+ ComposerHandleCache mOutputBufferCache;
+
+ std::unordered_map<Layer, std::unique_ptr<ComposerLayerResource>> mLayerResources;
+};
+
+class ComposerResources {
+ private:
+ template <bool isBuffer>
+ class ReplacedHandle;
+
+ public:
+ static std::unique_ptr<ComposerResources> create() {
+ auto resources = std::make_unique<ComposerResources>();
+ return resources->init() ? std::move(resources) : nullptr;
+ }
+
+ ComposerResources() = default;
+ virtual ~ComposerResources() = default;
+
+ bool init() { return mImporter.init(); }
+
+ using RemoveDisplay =
+ std::function<void(Display display, bool isVirtual, const std::vector<Layer>& layers)>;
+ void clear(RemoveDisplay removeDisplay) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ for (const auto& displayKey : mDisplayResources) {
+ Display display = displayKey.first;
+ const ComposerDisplayResource& displayResource = *displayKey.second;
+ removeDisplay(display, displayResource.isVirtual(), displayResource.getLayers());
+ }
+ mDisplayResources.clear();
+ }
+
+ Error addPhysicalDisplay(Display display) {
+ auto displayResource =
+ createDisplayResource(ComposerDisplayResource::DisplayType::PHYSICAL, 0);
+
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ auto result = mDisplayResources.emplace(display, std::move(displayResource));
+ return result.second ? Error::NONE : Error::BAD_DISPLAY;
+ }
+
+ Error addVirtualDisplay(Display display, uint32_t outputBufferCacheSize) {
+ auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::VIRTUAL,
+ outputBufferCacheSize);
+
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ auto result = mDisplayResources.emplace(display, std::move(displayResource));
+ return result.second ? Error::NONE : Error::BAD_DISPLAY;
+ }
+
+ Error removeDisplay(Display display) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ return mDisplayResources.erase(display) > 0 ? Error::NONE : Error::BAD_DISPLAY;
+ }
+
+ Error setDisplayClientTargetCacheSize(Display display, uint32_t clientTargetCacheSize) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+ if (!displayResource) {
+ return Error::BAD_DISPLAY;
+ }
+
+ return displayResource->initClientTargetCache(clientTargetCacheSize) ? Error::NONE
+ : Error::BAD_PARAMETER;
+ }
+
+ Error addLayer(Display display, Layer layer, uint32_t bufferCacheSize) {
+ auto layerResource = createLayerResource(bufferCacheSize);
+
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+ if (!displayResource) {
+ return Error::BAD_DISPLAY;
+ }
+
+ return displayResource->addLayer(layer, std::move(layerResource)) ? Error::NONE
+ : Error::BAD_LAYER;
+ }
+
+ Error removeLayer(Display display, Layer layer) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+ if (!displayResource) {
+ return Error::BAD_DISPLAY;
+ }
+
+ return displayResource->removeLayer(layer) ? Error::NONE : Error::BAD_LAYER;
+ }
+
+ using ReplacedBufferHandle = ReplacedHandle<true>;
+ using ReplacedStreamHandle = ReplacedHandle<false>;
+
+ Error getDisplayClientTarget(Display display, uint32_t slot, bool fromCache,
+ const native_handle_t* rawHandle,
+ const native_handle_t** outBufferHandle,
+ ReplacedBufferHandle* outReplacedBuffer) {
+ return getHandle<Cache::CLIENT_TARGET>(display, 0, slot, fromCache, rawHandle,
+ outBufferHandle, outReplacedBuffer);
+ }
+
+ Error getDisplayOutputBuffer(Display display, uint32_t slot, bool fromCache,
+ const native_handle_t* rawHandle,
+ const native_handle_t** outBufferHandle,
+ ReplacedBufferHandle* outReplacedBuffer) {
+ return getHandle<Cache::OUTPUT_BUFFER>(display, 0, slot, fromCache, rawHandle,
+ outBufferHandle, outReplacedBuffer);
+ }
+
+ Error getLayerBuffer(Display display, Layer layer, uint32_t slot, bool fromCache,
+ const native_handle_t* rawHandle, const native_handle_t** outBufferHandle,
+ ReplacedBufferHandle* outReplacedBuffer) {
+ return getHandle<Cache::LAYER_BUFFER>(display, layer, slot, fromCache, rawHandle,
+ outBufferHandle, outReplacedBuffer);
+ }
+
+ Error getLayerSidebandStream(Display display, Layer layer, const native_handle_t* rawHandle,
+ const native_handle_t** outStreamHandle,
+ ReplacedStreamHandle* outReplacedStream) {
+ return getHandle<Cache::LAYER_SIDEBAND_STREAM>(display, layer, 0, false, rawHandle,
+ outStreamHandle, outReplacedStream);
+ }
+
+ protected:
+ virtual std::unique_ptr<ComposerDisplayResource> createDisplayResource(
+ ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) {
+ return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
+ }
+
+ virtual std::unique_ptr<ComposerLayerResource> createLayerResource(uint32_t bufferCacheSize) {
+ return std::make_unique<ComposerLayerResource>(mImporter, bufferCacheSize);
+ }
+
+ ComposerDisplayResource* findDisplayResourceLocked(Display display) {
+ auto iter = mDisplayResources.find(display);
+ if (iter == mDisplayResources.end()) {
+ return nullptr;
+ }
+ return iter->second.get();
+ }
+
+ ComposerHandleImporter mImporter;
+
+ std::mutex mDisplayResourcesMutex;
+ std::unordered_map<Display, std::unique_ptr<ComposerDisplayResource>> mDisplayResources;
+
+ private:
+ enum class Cache {
+ CLIENT_TARGET,
+ OUTPUT_BUFFER,
+ LAYER_BUFFER,
+ LAYER_SIDEBAND_STREAM,
+ };
+
+ // When a buffer in the cache is replaced by a new one, we must keep it
+ // alive until it has been replaced in ComposerHal.
+ template <bool isBuffer>
+ class ReplacedHandle {
+ public:
+ ReplacedHandle() = default;
+ ReplacedHandle(const ReplacedHandle&) = delete;
+ ReplacedHandle& operator=(const ReplacedHandle&) = delete;
+
+ ~ReplacedHandle() { reset(); }
+
+ void reset(ComposerHandleImporter* importer = nullptr,
+ const native_handle_t* handle = nullptr) {
+ if (mHandle) {
+ if (isBuffer) {
+ mImporter->freeBuffer(mHandle);
+ } else {
+ mImporter->freeStream(mHandle);
+ }
+ }
+
+ mImporter = importer;
+ mHandle = handle;
+ }
+
+ private:
+ ComposerHandleImporter* mImporter = nullptr;
+ const native_handle_t* mHandle = nullptr;
+ };
+
+ template <Cache cache, bool isBuffer>
+ Error getHandle(Display display, Layer layer, uint32_t slot, bool fromCache,
+ const native_handle_t* rawHandle, const native_handle_t** outHandle,
+ ReplacedHandle<isBuffer>* outReplacedHandle) {
+ Error error;
+
+ // import the raw handle (or ignore raw handle when fromCache is true)
+ const native_handle_t* importedHandle = nullptr;
+ if (!fromCache) {
+ error = (isBuffer) ? mImporter.importBuffer(rawHandle, &importedHandle)
+ : mImporter.importStream(rawHandle, &importedHandle);
+ if (error != Error::NONE) {
+ return error;
+ }
+ }
+
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+
+ // find display/layer resource
+ const bool needLayerResource =
+ (cache == Cache::LAYER_BUFFER || cache == Cache::LAYER_SIDEBAND_STREAM);
+ ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+ ComposerLayerResource* layerResource = (displayResource && needLayerResource)
+ ? displayResource->findLayerResource(layer)
+ : nullptr;
+
+ // lookup or update cache
+ const native_handle_t* replacedHandle = nullptr;
+ if (displayResource && (!needLayerResource || layerResource)) {
+ switch (cache) {
+ case Cache::CLIENT_TARGET:
+ error = displayResource->getClientTarget(slot, fromCache, importedHandle,
+ outHandle, &replacedHandle);
+ break;
+ case Cache::OUTPUT_BUFFER:
+ error = displayResource->getOutputBuffer(slot, fromCache, importedHandle,
+ outHandle, &replacedHandle);
+ break;
+ case Cache::LAYER_BUFFER:
+ error = layerResource->getBuffer(slot, fromCache, importedHandle, outHandle,
+ &replacedHandle);
+ break;
+ case Cache::LAYER_SIDEBAND_STREAM:
+ error = layerResource->getSidebandStream(slot, fromCache, importedHandle,
+ outHandle, &replacedHandle);
+ break;
+ default:
+ error = Error::BAD_PARAMETER;
+ break;
+ }
+
+ if (error != Error::NONE) {
+ ALOGW("invalid cache %d slot %d", int(cache), int(slot));
+ }
+ } else if (!displayResource) {
+ error = Error::BAD_DISPLAY;
+ } else {
+ error = Error::BAD_LAYER;
+ }
+
+ // clean up on errors
+ if (error != Error::NONE) {
+ if (!fromCache) {
+ if (isBuffer) {
+ mImporter.freeBuffer(importedHandle);
+ } else {
+ mImporter.freeStream(importedHandle);
+ }
+ }
+ return error;
+ }
+
+ outReplacedHandle->reset(&mImporter, replacedHandle);
+
+ return Error::NONE;
+ }
+};
+
+} // namespace hal
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp b/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
new file mode 100644
index 0000000..420a1f6
--- /dev/null
+++ b/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
@@ -0,0 +1,76 @@
+// Copyright 2010 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.
+
+cc_library_shared {
+ name: "libhwc2on1adapter",
+ vendor: true,
+
+ clang: true,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-user-defined-warnings",
+ ],
+ cppflags: [
+ "-Weverything",
+ "-Wunused",
+ "-Wunreachable-code",
+
+ // The static constructors and destructors in this library have not been noted to
+ // introduce significant overheads
+ "-Wno-exit-time-destructors",
+ "-Wno-global-constructors",
+
+ // We only care about compiling as C++14
+ "-Wno-c++98-compat-pedantic",
+
+ // android/sensors.h uses nested anonymous unions and anonymous structs
+ "-Wno-nested-anon-types",
+ "-Wno-gnu-anonymous-struct",
+
+ // Don't warn about struct padding
+ "-Wno-padded",
+
+ // hwcomposer2.h features switch covering all cases.
+ "-Wno-covered-switch-default",
+
+ // hwcomposer.h features zero size array.
+ "-Wno-zero-length-array",
+
+ // Disabling warning specific to hwc2on1adapter code
+ "-Wno-double-promotion",
+ "-Wno-sign-conversion",
+ "-Wno-switch-enum",
+ "-Wno-float-equal",
+ "-Wno-shorten-64-to-32",
+ "-Wno-sign-compare",
+ "-Wno-missing-prototypes",
+ ],
+
+ srcs: [
+ "HWC2On1Adapter.cpp",
+ "MiniFence.cpp",
+ ],
+
+ shared_libs: [
+ "libutils",
+ "libcutils",
+ "liblog",
+ "libhardware",
+ ],
+
+ export_include_dirs: ["include"],
+
+ export_shared_lib_headers: ["libutils"],
+}
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/CleanSpec.mk b/graphics/composer/2.1/utils/hwc2on1adapter/CleanSpec.mk
new file mode 100644
index 0000000..7fc2216
--- /dev/null
+++ b/graphics/composer/2.1/utils/hwc2on1adapter/CleanSpec.mk
@@ -0,0 +1,52 @@
+# Copyright (C) 2017 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libhwc2on1adapter_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libhwc2on1adapter.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/libhwc2on1adapter.so)
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp b/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp
new file mode 100644
index 0000000..77f06bb
--- /dev/null
+++ b/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -0,0 +1,2637 @@
+/*
+ * Copyright 2015 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.
+ */
+
+#include "hwc2on1adapter/HWC2On1Adapter.h"
+
+//#define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "HWC2On1Adapter"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+
+#include <inttypes.h>
+
+#include <chrono>
+#include <cstdlib>
+#include <sstream>
+
+#include <hardware/hwcomposer.h>
+#include <log/log.h>
+#include <utils/Trace.h>
+
+using namespace std::chrono_literals;
+
+static uint8_t getMinorVersion(struct hwc_composer_device_1* device)
+{
+ auto version = device->common.version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK;
+ return (version >> 16) & 0xF;
+}
+
+template <typename PFN, typename T>
+static hwc2_function_pointer_t asFP(T function)
+{
+ static_assert(std::is_same<PFN, T>::value, "Incompatible function pointer");
+ return reinterpret_cast<hwc2_function_pointer_t>(function);
+}
+
+using namespace HWC2;
+
+static constexpr Attribute ColorMode = static_cast<Attribute>(6);
+
+namespace android {
+
+class HWC2On1Adapter::Callbacks : public hwc_procs_t {
+ public:
+ explicit Callbacks(HWC2On1Adapter& adapter) : mAdapter(adapter) {
+ invalidate = &invalidateHook;
+ vsync = &vsyncHook;
+ hotplug = &hotplugHook;
+ }
+
+ static void invalidateHook(const hwc_procs_t* procs) {
+ auto callbacks = static_cast<const Callbacks*>(procs);
+ callbacks->mAdapter.hwc1Invalidate();
+ }
+
+ static void vsyncHook(const hwc_procs_t* procs, int display,
+ int64_t timestamp) {
+ auto callbacks = static_cast<const Callbacks*>(procs);
+ callbacks->mAdapter.hwc1Vsync(display, timestamp);
+ }
+
+ static void hotplugHook(const hwc_procs_t* procs, int display,
+ int connected) {
+ auto callbacks = static_cast<const Callbacks*>(procs);
+ callbacks->mAdapter.hwc1Hotplug(display, connected);
+ }
+
+ private:
+ HWC2On1Adapter& mAdapter;
+};
+
+static int closeHook(hw_device_t* /*device*/)
+{
+ // Do nothing, since the real work is done in the class destructor, but we
+ // need to provide a valid function pointer for hwc2_close to call
+ return 0;
+}
+
+HWC2On1Adapter::HWC2On1Adapter(hwc_composer_device_1_t* hwc1Device)
+ : mDumpString(),
+ mHwc1Device(hwc1Device),
+ mHwc1MinorVersion(getMinorVersion(hwc1Device)),
+ mHwc1SupportsVirtualDisplays(false),
+ mHwc1SupportsBackgroundColor(false),
+ mHwc1Callbacks(std::make_unique<Callbacks>(*this)),
+ mCapabilities(),
+ mLayers(),
+ mHwc1VirtualDisplay(),
+ mStateMutex(),
+ mCallbacks(),
+ mHasPendingInvalidate(false),
+ mPendingVsyncs(),
+ mPendingHotplugs(),
+ mDisplays(),
+ mHwc1DisplayMap()
+{
+ common.close = closeHook;
+ getCapabilities = getCapabilitiesHook;
+ getFunction = getFunctionHook;
+ populateCapabilities();
+ populatePrimary();
+ mHwc1Device->registerProcs(mHwc1Device,
+ static_cast<const hwc_procs_t*>(mHwc1Callbacks.get()));
+}
+
+HWC2On1Adapter::~HWC2On1Adapter() {
+ hwc_close_1(mHwc1Device);
+}
+
+void HWC2On1Adapter::doGetCapabilities(uint32_t* outCount,
+ int32_t* outCapabilities) {
+ if (outCapabilities == nullptr) {
+ *outCount = mCapabilities.size();
+ return;
+ }
+
+ auto capabilityIter = mCapabilities.cbegin();
+ for (size_t written = 0; written < *outCount; ++written) {
+ if (capabilityIter == mCapabilities.cend()) {
+ return;
+ }
+ outCapabilities[written] = static_cast<int32_t>(*capabilityIter);
+ ++capabilityIter;
+ }
+}
+
+hwc2_function_pointer_t HWC2On1Adapter::doGetFunction(
+ FunctionDescriptor descriptor) {
+ switch (descriptor) {
+ // Device functions
+ case FunctionDescriptor::CreateVirtualDisplay:
+ return asFP<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(
+ createVirtualDisplayHook);
+ case FunctionDescriptor::DestroyVirtualDisplay:
+ return asFP<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(
+ destroyVirtualDisplayHook);
+ case FunctionDescriptor::Dump:
+ return asFP<HWC2_PFN_DUMP>(dumpHook);
+ case FunctionDescriptor::GetMaxVirtualDisplayCount:
+ return asFP<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(
+ getMaxVirtualDisplayCountHook);
+ case FunctionDescriptor::RegisterCallback:
+ return asFP<HWC2_PFN_REGISTER_CALLBACK>(registerCallbackHook);
+
+ // Display functions
+ case FunctionDescriptor::AcceptDisplayChanges:
+ return asFP<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(
+ displayHook<decltype(&Display::acceptChanges),
+ &Display::acceptChanges>);
+ case FunctionDescriptor::CreateLayer:
+ return asFP<HWC2_PFN_CREATE_LAYER>(
+ displayHook<decltype(&Display::createLayer),
+ &Display::createLayer, hwc2_layer_t*>);
+ case FunctionDescriptor::DestroyLayer:
+ return asFP<HWC2_PFN_DESTROY_LAYER>(
+ displayHook<decltype(&Display::destroyLayer),
+ &Display::destroyLayer, hwc2_layer_t>);
+ case FunctionDescriptor::GetActiveConfig:
+ return asFP<HWC2_PFN_GET_ACTIVE_CONFIG>(
+ displayHook<decltype(&Display::getActiveConfig),
+ &Display::getActiveConfig, hwc2_config_t*>);
+ case FunctionDescriptor::GetChangedCompositionTypes:
+ return asFP<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(
+ displayHook<decltype(&Display::getChangedCompositionTypes),
+ &Display::getChangedCompositionTypes, uint32_t*,
+ hwc2_layer_t*, int32_t*>);
+ case FunctionDescriptor::GetColorModes:
+ return asFP<HWC2_PFN_GET_COLOR_MODES>(
+ displayHook<decltype(&Display::getColorModes),
+ &Display::getColorModes, uint32_t*, int32_t*>);
+ case FunctionDescriptor::GetDisplayAttribute:
+ return asFP<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(
+ getDisplayAttributeHook);
+ case FunctionDescriptor::GetDisplayConfigs:
+ return asFP<HWC2_PFN_GET_DISPLAY_CONFIGS>(
+ displayHook<decltype(&Display::getConfigs),
+ &Display::getConfigs, uint32_t*, hwc2_config_t*>);
+ case FunctionDescriptor::GetDisplayName:
+ return asFP<HWC2_PFN_GET_DISPLAY_NAME>(
+ displayHook<decltype(&Display::getName),
+ &Display::getName, uint32_t*, char*>);
+ case FunctionDescriptor::GetDisplayRequests:
+ return asFP<HWC2_PFN_GET_DISPLAY_REQUESTS>(
+ displayHook<decltype(&Display::getRequests),
+ &Display::getRequests, int32_t*, uint32_t*, hwc2_layer_t*,
+ int32_t*>);
+ case FunctionDescriptor::GetDisplayType:
+ return asFP<HWC2_PFN_GET_DISPLAY_TYPE>(
+ displayHook<decltype(&Display::getType),
+ &Display::getType, int32_t*>);
+ case FunctionDescriptor::GetDozeSupport:
+ return asFP<HWC2_PFN_GET_DOZE_SUPPORT>(
+ displayHook<decltype(&Display::getDozeSupport),
+ &Display::getDozeSupport, int32_t*>);
+ case FunctionDescriptor::GetHdrCapabilities:
+ return asFP<HWC2_PFN_GET_HDR_CAPABILITIES>(
+ displayHook<decltype(&Display::getHdrCapabilities),
+ &Display::getHdrCapabilities, uint32_t*, int32_t*, float*,
+ float*, float*>);
+ case FunctionDescriptor::GetReleaseFences:
+ return asFP<HWC2_PFN_GET_RELEASE_FENCES>(
+ displayHook<decltype(&Display::getReleaseFences),
+ &Display::getReleaseFences, uint32_t*, hwc2_layer_t*,
+ int32_t*>);
+ case FunctionDescriptor::PresentDisplay:
+ return asFP<HWC2_PFN_PRESENT_DISPLAY>(
+ displayHook<decltype(&Display::present),
+ &Display::present, int32_t*>);
+ case FunctionDescriptor::SetActiveConfig:
+ return asFP<HWC2_PFN_SET_ACTIVE_CONFIG>(
+ displayHook<decltype(&Display::setActiveConfig),
+ &Display::setActiveConfig, hwc2_config_t>);
+ case FunctionDescriptor::SetClientTarget:
+ return asFP<HWC2_PFN_SET_CLIENT_TARGET>(
+ displayHook<decltype(&Display::setClientTarget),
+ &Display::setClientTarget, buffer_handle_t, int32_t,
+ int32_t, hwc_region_t>);
+ case FunctionDescriptor::SetColorMode:
+ return asFP<HWC2_PFN_SET_COLOR_MODE>(setColorModeHook);
+ case FunctionDescriptor::SetColorTransform:
+ return asFP<HWC2_PFN_SET_COLOR_TRANSFORM>(setColorTransformHook);
+ case FunctionDescriptor::SetOutputBuffer:
+ return asFP<HWC2_PFN_SET_OUTPUT_BUFFER>(
+ displayHook<decltype(&Display::setOutputBuffer),
+ &Display::setOutputBuffer, buffer_handle_t, int32_t>);
+ case FunctionDescriptor::SetPowerMode:
+ return asFP<HWC2_PFN_SET_POWER_MODE>(setPowerModeHook);
+ case FunctionDescriptor::SetVsyncEnabled:
+ return asFP<HWC2_PFN_SET_VSYNC_ENABLED>(setVsyncEnabledHook);
+ case FunctionDescriptor::ValidateDisplay:
+ return asFP<HWC2_PFN_VALIDATE_DISPLAY>(
+ displayHook<decltype(&Display::validate),
+ &Display::validate, uint32_t*, uint32_t*>);
+ case FunctionDescriptor::GetClientTargetSupport:
+ return asFP<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(
+ displayHook<decltype(&Display::getClientTargetSupport),
+ &Display::getClientTargetSupport, uint32_t, uint32_t,
+ int32_t, int32_t>);
+
+ // Layer functions
+ case FunctionDescriptor::SetCursorPosition:
+ return asFP<HWC2_PFN_SET_CURSOR_POSITION>(
+ layerHook<decltype(&Layer::setCursorPosition),
+ &Layer::setCursorPosition, int32_t, int32_t>);
+ case FunctionDescriptor::SetLayerBuffer:
+ return asFP<HWC2_PFN_SET_LAYER_BUFFER>(
+ layerHook<decltype(&Layer::setBuffer), &Layer::setBuffer,
+ buffer_handle_t, int32_t>);
+ case FunctionDescriptor::SetLayerSurfaceDamage:
+ return asFP<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(
+ layerHook<decltype(&Layer::setSurfaceDamage),
+ &Layer::setSurfaceDamage, hwc_region_t>);
+
+ // Layer state functions
+ case FunctionDescriptor::SetLayerBlendMode:
+ return asFP<HWC2_PFN_SET_LAYER_BLEND_MODE>(
+ setLayerBlendModeHook);
+ case FunctionDescriptor::SetLayerColor:
+ return asFP<HWC2_PFN_SET_LAYER_COLOR>(
+ layerHook<decltype(&Layer::setColor), &Layer::setColor,
+ hwc_color_t>);
+ case FunctionDescriptor::SetLayerCompositionType:
+ return asFP<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(
+ setLayerCompositionTypeHook);
+ case FunctionDescriptor::SetLayerDataspace:
+ return asFP<HWC2_PFN_SET_LAYER_DATASPACE>(setLayerDataspaceHook);
+ case FunctionDescriptor::SetLayerDisplayFrame:
+ return asFP<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(
+ layerHook<decltype(&Layer::setDisplayFrame),
+ &Layer::setDisplayFrame, hwc_rect_t>);
+ case FunctionDescriptor::SetLayerPlaneAlpha:
+ return asFP<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(
+ layerHook<decltype(&Layer::setPlaneAlpha),
+ &Layer::setPlaneAlpha, float>);
+ case FunctionDescriptor::SetLayerSidebandStream:
+ return asFP<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(
+ layerHook<decltype(&Layer::setSidebandStream),
+ &Layer::setSidebandStream, const native_handle_t*>);
+ case FunctionDescriptor::SetLayerSourceCrop:
+ return asFP<HWC2_PFN_SET_LAYER_SOURCE_CROP>(
+ layerHook<decltype(&Layer::setSourceCrop),
+ &Layer::setSourceCrop, hwc_frect_t>);
+ case FunctionDescriptor::SetLayerTransform:
+ return asFP<HWC2_PFN_SET_LAYER_TRANSFORM>(setLayerTransformHook);
+ case FunctionDescriptor::SetLayerVisibleRegion:
+ return asFP<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(
+ layerHook<decltype(&Layer::setVisibleRegion),
+ &Layer::setVisibleRegion, hwc_region_t>);
+ case FunctionDescriptor::SetLayerZOrder:
+ return asFP<HWC2_PFN_SET_LAYER_Z_ORDER>(setLayerZOrderHook);
+
+ default:
+ ALOGE("doGetFunction: Unknown function descriptor: %d (%s)",
+ static_cast<int32_t>(descriptor),
+ to_string(descriptor).c_str());
+ return nullptr;
+ }
+}
+
+// Device functions
+
+Error HWC2On1Adapter::createVirtualDisplay(uint32_t width,
+ uint32_t height, hwc2_display_t* outDisplay) {
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ if (mHwc1VirtualDisplay) {
+ // We have already allocated our only HWC1 virtual display
+ ALOGE("createVirtualDisplay: HWC1 virtual display already allocated");
+ return Error::NoResources;
+ }
+
+ mHwc1VirtualDisplay = std::make_shared<HWC2On1Adapter::Display>(*this,
+ HWC2::DisplayType::Virtual);
+ mHwc1VirtualDisplay->populateConfigs(width, height);
+ const auto displayId = mHwc1VirtualDisplay->getId();
+ mHwc1DisplayMap[HWC_DISPLAY_VIRTUAL] = displayId;
+ mHwc1VirtualDisplay->setHwc1Id(HWC_DISPLAY_VIRTUAL);
+ mDisplays.emplace(displayId, mHwc1VirtualDisplay);
+ *outDisplay = displayId;
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::destroyVirtualDisplay(hwc2_display_t displayId) {
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ if (!mHwc1VirtualDisplay || (mHwc1VirtualDisplay->getId() != displayId)) {
+ return Error::BadDisplay;
+ }
+
+ mHwc1VirtualDisplay.reset();
+ mHwc1DisplayMap.erase(HWC_DISPLAY_VIRTUAL);
+ mDisplays.erase(displayId);
+
+ return Error::None;
+}
+
+void HWC2On1Adapter::dump(uint32_t* outSize, char* outBuffer) {
+ if (outBuffer != nullptr) {
+ auto copiedBytes = mDumpString.copy(outBuffer, *outSize);
+ *outSize = static_cast<uint32_t>(copiedBytes);
+ return;
+ }
+
+ std::stringstream output;
+
+ output << "-- HWC2On1Adapter --\n";
+
+ output << "Adapting to a HWC 1." << static_cast<int>(mHwc1MinorVersion) <<
+ " device\n";
+
+ // Attempt to acquire the lock for 1 second, but proceed without the lock
+ // after that, so we can still get some information if we're deadlocked
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex,
+ std::defer_lock);
+ lock.try_lock_for(1s);
+
+ if (mCapabilities.empty()) {
+ output << "Capabilities: None\n";
+ } else {
+ output << "Capabilities:\n";
+ for (auto capability : mCapabilities) {
+ output << " " << to_string(capability) << '\n';
+ }
+ }
+
+ output << "Displays:\n";
+ for (const auto& element : mDisplays) {
+ const auto& display = element.second;
+ output << display->dump();
+ }
+ output << '\n';
+
+ // Release the lock before calling into HWC1, and since we no longer require
+ // mutual exclusion to access mCapabilities or mDisplays
+ lock.unlock();
+
+ if (mHwc1Device->dump) {
+ output << "HWC1 dump:\n";
+ std::vector<char> hwc1Dump(4096);
+ // Call with size - 1 to preserve a null character at the end
+ mHwc1Device->dump(mHwc1Device, hwc1Dump.data(),
+ static_cast<int>(hwc1Dump.size() - 1));
+ output << hwc1Dump.data();
+ }
+
+ mDumpString = output.str();
+ *outSize = static_cast<uint32_t>(mDumpString.size());
+}
+
+uint32_t HWC2On1Adapter::getMaxVirtualDisplayCount() {
+ return mHwc1SupportsVirtualDisplays ? 1 : 0;
+}
+
+static bool isValid(Callback descriptor) {
+ switch (descriptor) {
+ case Callback::Hotplug: // Fall-through
+ case Callback::Refresh: // Fall-through
+ case Callback::Vsync: return true;
+ default: return false;
+ }
+}
+
+Error HWC2On1Adapter::registerCallback(Callback descriptor,
+ hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer) {
+ if (!isValid(descriptor)) {
+ return Error::BadParameter;
+ }
+
+ ALOGV("registerCallback(%s, %p, %p)", to_string(descriptor).c_str(),
+ callbackData, pointer);
+
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ if (pointer != nullptr) {
+ mCallbacks[descriptor] = {callbackData, pointer};
+ } else {
+ ALOGI("unregisterCallback(%s)", to_string(descriptor).c_str());
+ mCallbacks.erase(descriptor);
+ return Error::None;
+ }
+
+ bool hasPendingInvalidate = false;
+ std::vector<hwc2_display_t> displayIds;
+ std::vector<std::pair<hwc2_display_t, int64_t>> pendingVsyncs;
+ std::vector<std::pair<hwc2_display_t, int>> pendingHotplugs;
+
+ if (descriptor == Callback::Refresh) {
+ hasPendingInvalidate = mHasPendingInvalidate;
+ if (hasPendingInvalidate) {
+ for (auto& displayPair : mDisplays) {
+ displayIds.emplace_back(displayPair.first);
+ }
+ }
+ mHasPendingInvalidate = false;
+ } else if (descriptor == Callback::Vsync) {
+ for (auto pending : mPendingVsyncs) {
+ auto hwc1DisplayId = pending.first;
+ if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
+ ALOGE("hwc1Vsync: Couldn't find display for HWC1 id %d",
+ hwc1DisplayId);
+ continue;
+ }
+ auto displayId = mHwc1DisplayMap[hwc1DisplayId];
+ auto timestamp = pending.second;
+ pendingVsyncs.emplace_back(displayId, timestamp);
+ }
+ mPendingVsyncs.clear();
+ } else if (descriptor == Callback::Hotplug) {
+ // Hotplug the primary display
+ pendingHotplugs.emplace_back(mHwc1DisplayMap[HWC_DISPLAY_PRIMARY],
+ static_cast<int32_t>(Connection::Connected));
+
+ for (auto pending : mPendingHotplugs) {
+ auto hwc1DisplayId = pending.first;
+ if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
+ ALOGE("hwc1Hotplug: Couldn't find display for HWC1 id %d",
+ hwc1DisplayId);
+ continue;
+ }
+ auto displayId = mHwc1DisplayMap[hwc1DisplayId];
+ auto connected = pending.second;
+ pendingHotplugs.emplace_back(displayId, connected);
+ }
+ }
+
+ // Call pending callbacks without the state lock held
+ lock.unlock();
+
+ if (hasPendingInvalidate) {
+ auto refresh = reinterpret_cast<HWC2_PFN_REFRESH>(pointer);
+ for (auto displayId : displayIds) {
+ refresh(callbackData, displayId);
+ }
+ }
+ if (!pendingVsyncs.empty()) {
+ auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(pointer);
+ for (auto& pendingVsync : pendingVsyncs) {
+ vsync(callbackData, pendingVsync.first, pendingVsync.second);
+ }
+ }
+ if (!pendingHotplugs.empty()) {
+ auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(pointer);
+ for (auto& pendingHotplug : pendingHotplugs) {
+ hotplug(callbackData, pendingHotplug.first, pendingHotplug.second);
+ }
+ }
+ return Error::None;
+}
+
+// Display functions
+
+std::atomic<hwc2_display_t> HWC2On1Adapter::Display::sNextId(1);
+
+HWC2On1Adapter::Display::Display(HWC2On1Adapter& device, HWC2::DisplayType type)
+ : mId(sNextId++),
+ mDevice(device),
+ mStateMutex(),
+ mHwc1RequestedContents(nullptr),
+ mRetireFence(),
+ mChanges(),
+ mHwc1Id(-1),
+ mConfigs(),
+ mActiveConfig(nullptr),
+ mActiveColorMode(static_cast<android_color_mode_t>(-1)),
+ mName(),
+ mType(type),
+ mPowerMode(PowerMode::Off),
+ mVsyncEnabled(Vsync::Invalid),
+ mClientTarget(),
+ mOutputBuffer(),
+ mHasColorTransform(false),
+ mLayers(),
+ mHwc1LayerMap(),
+ mNumAvailableRects(0),
+ mNextAvailableRect(nullptr),
+ mGeometryChanged(false)
+ {}
+
+Error HWC2On1Adapter::Display::acceptChanges() {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!mChanges) {
+ ALOGV("[%" PRIu64 "] acceptChanges failed, not validated", mId);
+ return Error::NotValidated;
+ }
+
+ ALOGV("[%" PRIu64 "] acceptChanges", mId);
+
+ for (auto& change : mChanges->getTypeChanges()) {
+ auto layerId = change.first;
+ auto type = change.second;
+ if (mDevice.mLayers.count(layerId) == 0) {
+ // This should never happen but somehow does.
+ ALOGW("Cannot accept change for unknown layer (%" PRIu64 ")",
+ layerId);
+ continue;
+ }
+ auto layer = mDevice.mLayers[layerId];
+ layer->setCompositionType(type);
+ }
+
+ mChanges->clearTypeChanges();
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::createLayer(hwc2_layer_t* outLayerId) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ auto layer = *mLayers.emplace(std::make_shared<Layer>(*this));
+ mDevice.mLayers.emplace(std::make_pair(layer->getId(), layer));
+ *outLayerId = layer->getId();
+ ALOGV("[%" PRIu64 "] created layer %" PRIu64, mId, *outLayerId);
+ markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::destroyLayer(hwc2_layer_t layerId) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ const auto mapLayer = mDevice.mLayers.find(layerId);
+ if (mapLayer == mDevice.mLayers.end()) {
+ ALOGV("[%" PRIu64 "] destroyLayer(%" PRIu64 ") failed: no such layer",
+ mId, layerId);
+ return Error::BadLayer;
+ }
+ const auto layer = mapLayer->second;
+ mDevice.mLayers.erase(mapLayer);
+ const auto zRange = mLayers.equal_range(layer);
+ for (auto current = zRange.first; current != zRange.second; ++current) {
+ if (**current == *layer) {
+ current = mLayers.erase(current);
+ break;
+ }
+ }
+ ALOGV("[%" PRIu64 "] destroyed layer %" PRIu64, mId, layerId);
+ markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getActiveConfig(hwc2_config_t* outConfig) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!mActiveConfig) {
+ ALOGV("[%" PRIu64 "] getActiveConfig --> %s", mId,
+ to_string(Error::BadConfig).c_str());
+ return Error::BadConfig;
+ }
+ auto configId = mActiveConfig->getId();
+ ALOGV("[%" PRIu64 "] getActiveConfig --> %u", mId, configId);
+ *outConfig = configId;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getAttribute(hwc2_config_t configId,
+ Attribute attribute, int32_t* outValue) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) {
+ ALOGV("[%" PRIu64 "] getAttribute failed: bad config (%u)", mId,
+ configId);
+ return Error::BadConfig;
+ }
+ *outValue = mConfigs[configId]->getAttribute(attribute);
+ ALOGV("[%" PRIu64 "] getAttribute(%u, %s) --> %d", mId, configId,
+ to_string(attribute).c_str(), *outValue);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getChangedCompositionTypes(
+ uint32_t* outNumElements, hwc2_layer_t* outLayers, int32_t* outTypes) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!mChanges) {
+ ALOGE("[%" PRIu64 "] getChangedCompositionTypes failed: not validated",
+ mId);
+ return Error::NotValidated;
+ }
+
+ if ((outLayers == nullptr) || (outTypes == nullptr)) {
+ *outNumElements = mChanges->getTypeChanges().size();
+ return Error::None;
+ }
+
+ uint32_t numWritten = 0;
+ for (const auto& element : mChanges->getTypeChanges()) {
+ if (numWritten == *outNumElements) {
+ break;
+ }
+ auto layerId = element.first;
+ auto intType = static_cast<int32_t>(element.second);
+ ALOGV("Adding %" PRIu64 " %s", layerId,
+ to_string(element.second).c_str());
+ outLayers[numWritten] = layerId;
+ outTypes[numWritten] = intType;
+ ++numWritten;
+ }
+ *outNumElements = numWritten;
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getColorModes(uint32_t* outNumModes,
+ int32_t* outModes) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!outModes) {
+ *outNumModes = mColorModes.size();
+ return Error::None;
+ }
+ uint32_t numModes = std::min(*outNumModes,
+ static_cast<uint32_t>(mColorModes.size()));
+ std::copy_n(mColorModes.cbegin(), numModes, outModes);
+ *outNumModes = numModes;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getConfigs(uint32_t* outNumConfigs,
+ hwc2_config_t* outConfigs) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!outConfigs) {
+ *outNumConfigs = mConfigs.size();
+ return Error::None;
+ }
+ uint32_t numWritten = 0;
+ for (const auto& config : mConfigs) {
+ if (numWritten == *outNumConfigs) {
+ break;
+ }
+ outConfigs[numWritten] = config->getId();
+ ++numWritten;
+ }
+ *outNumConfigs = numWritten;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getDozeSupport(int32_t* outSupport) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (mDevice.mHwc1MinorVersion < 4 || mHwc1Id != 0) {
+ *outSupport = 0;
+ } else {
+ *outSupport = 1;
+ }
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getHdrCapabilities(uint32_t* outNumTypes,
+ int32_t* /*outTypes*/, float* /*outMaxLuminance*/,
+ float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/) {
+ // This isn't supported on HWC1, so per the HWC2 header, return numTypes = 0
+ *outNumTypes = 0;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getName(uint32_t* outSize, char* outName) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!outName) {
+ *outSize = mName.size();
+ return Error::None;
+ }
+ auto numCopied = mName.copy(outName, *outSize);
+ *outSize = numCopied;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getReleaseFences(uint32_t* outNumElements,
+ hwc2_layer_t* outLayers, int32_t* outFences) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ uint32_t numWritten = 0;
+ bool outputsNonNull = (outLayers != nullptr) && (outFences != nullptr);
+ for (const auto& layer : mLayers) {
+ if (outputsNonNull && (numWritten == *outNumElements)) {
+ break;
+ }
+
+ auto releaseFence = layer->getReleaseFence();
+ if (releaseFence != MiniFence::NO_FENCE) {
+ if (outputsNonNull) {
+ outLayers[numWritten] = layer->getId();
+ outFences[numWritten] = releaseFence->dup();
+ }
+ ++numWritten;
+ }
+ }
+ *outNumElements = numWritten;
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getRequests(int32_t* outDisplayRequests,
+ uint32_t* outNumElements, hwc2_layer_t* outLayers,
+ int32_t* outLayerRequests) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!mChanges) {
+ return Error::NotValidated;
+ }
+
+ if (outLayers == nullptr || outLayerRequests == nullptr) {
+ *outNumElements = mChanges->getNumLayerRequests();
+ return Error::None;
+ }
+
+ // Display requests (HWC2::DisplayRequest) are not supported by hwc1:
+ // A hwc1 has always zero requests for the client.
+ *outDisplayRequests = 0;
+
+ uint32_t numWritten = 0;
+ for (const auto& request : mChanges->getLayerRequests()) {
+ if (numWritten == *outNumElements) {
+ break;
+ }
+ outLayers[numWritten] = request.first;
+ outLayerRequests[numWritten] = static_cast<int32_t>(request.second);
+ ++numWritten;
+ }
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getType(int32_t* outType) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ *outType = static_cast<int32_t>(mType);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::present(int32_t* outRetireFence) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (mChanges) {
+ Error error = mDevice.setAllDisplays();
+ if (error != Error::None) {
+ ALOGE("[%" PRIu64 "] present: setAllDisplaysFailed (%s)", mId,
+ to_string(error).c_str());
+ return error;
+ }
+ }
+
+ *outRetireFence = mRetireFence.get()->dup();
+ ALOGV("[%" PRIu64 "] present returning retire fence %d", mId,
+ *outRetireFence);
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setActiveConfig(hwc2_config_t configId) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ auto config = getConfig(configId);
+ if (!config) {
+ return Error::BadConfig;
+ }
+ if (config == mActiveConfig) {
+ return Error::None;
+ }
+
+ if (mDevice.mHwc1MinorVersion >= 4) {
+ uint32_t hwc1Id = 0;
+ auto error = config->getHwc1IdForColorMode(mActiveColorMode, &hwc1Id);
+ if (error != Error::None) {
+ return error;
+ }
+
+ int intError = mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device,
+ mHwc1Id, static_cast<int>(hwc1Id));
+ if (intError != 0) {
+ ALOGE("setActiveConfig: Failed to set active config on HWC1 (%d)",
+ intError);
+ return Error::BadConfig;
+ }
+ mActiveConfig = config;
+ }
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setClientTarget(buffer_handle_t target,
+ int32_t acquireFence, int32_t /*dataspace*/, hwc_region_t /*damage*/) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ ALOGV("[%" PRIu64 "] setClientTarget(%p, %d)", mId, target, acquireFence);
+ mClientTarget.setBuffer(target);
+ mClientTarget.setFence(acquireFence);
+ // dataspace and damage can't be used by HWC1, so ignore them
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setColorMode(android_color_mode_t mode) {
+ std::unique_lock<std::recursive_mutex> lock (mStateMutex);
+
+ ALOGV("[%" PRIu64 "] setColorMode(%d)", mId, mode);
+
+ if (mode == mActiveColorMode) {
+ return Error::None;
+ }
+ if (mColorModes.count(mode) == 0) {
+ ALOGE("[%" PRIu64 "] Mode %d not found in mColorModes", mId, mode);
+ return Error::Unsupported;
+ }
+
+ uint32_t hwc1Config = 0;
+ auto error = mActiveConfig->getHwc1IdForColorMode(mode, &hwc1Config);
+ if (error != Error::None) {
+ return error;
+ }
+
+ ALOGV("[%" PRIu64 "] Setting HWC1 config %u", mId, hwc1Config);
+ int intError = mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device,
+ mHwc1Id, hwc1Config);
+ if (intError != 0) {
+ ALOGE("[%" PRIu64 "] Failed to set HWC1 config (%d)", mId, intError);
+ return Error::Unsupported;
+ }
+
+ mActiveColorMode = mode;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setColorTransform(android_color_transform_t hint) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ ALOGV("%" PRIu64 "] setColorTransform(%d)", mId,
+ static_cast<int32_t>(hint));
+ mHasColorTransform = (hint != HAL_COLOR_TRANSFORM_IDENTITY);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setOutputBuffer(buffer_handle_t buffer,
+ int32_t releaseFence) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ ALOGV("[%" PRIu64 "] setOutputBuffer(%p, %d)", mId, buffer, releaseFence);
+ mOutputBuffer.setBuffer(buffer);
+ mOutputBuffer.setFence(releaseFence);
+ return Error::None;
+}
+
+static bool isValid(PowerMode mode) {
+ switch (mode) {
+ case PowerMode::Off: // Fall-through
+ case PowerMode::DozeSuspend: // Fall-through
+ case PowerMode::Doze: // Fall-through
+ case PowerMode::On: return true;
+ }
+}
+
+static int getHwc1PowerMode(PowerMode mode) {
+ switch (mode) {
+ case PowerMode::Off: return HWC_POWER_MODE_OFF;
+ case PowerMode::DozeSuspend: return HWC_POWER_MODE_DOZE_SUSPEND;
+ case PowerMode::Doze: return HWC_POWER_MODE_DOZE;
+ case PowerMode::On: return HWC_POWER_MODE_NORMAL;
+ }
+}
+
+Error HWC2On1Adapter::Display::setPowerMode(PowerMode mode) {
+ if (!isValid(mode)) {
+ return Error::BadParameter;
+ }
+ if (mode == mPowerMode) {
+ return Error::None;
+ }
+
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ int error = 0;
+ if (mDevice.mHwc1MinorVersion < 4) {
+ error = mDevice.mHwc1Device->blank(mDevice.mHwc1Device, mHwc1Id,
+ mode == PowerMode::Off);
+ } else {
+ error = mDevice.mHwc1Device->setPowerMode(mDevice.mHwc1Device,
+ mHwc1Id, getHwc1PowerMode(mode));
+ }
+ ALOGE_IF(error != 0, "setPowerMode: Failed to set power mode on HWC1 (%d)",
+ error);
+
+ ALOGV("[%" PRIu64 "] setPowerMode(%s)", mId, to_string(mode).c_str());
+ mPowerMode = mode;
+ return Error::None;
+}
+
+static bool isValid(Vsync enable) {
+ switch (enable) {
+ case Vsync::Enable: // Fall-through
+ case Vsync::Disable: return true;
+ case Vsync::Invalid: return false;
+ }
+}
+
+Error HWC2On1Adapter::Display::setVsyncEnabled(Vsync enable) {
+ if (!isValid(enable)) {
+ return Error::BadParameter;
+ }
+ if (enable == mVsyncEnabled) {
+ return Error::None;
+ }
+
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ int error = mDevice.mHwc1Device->eventControl(mDevice.mHwc1Device,
+ mHwc1Id, HWC_EVENT_VSYNC, enable == Vsync::Enable);
+ ALOGE_IF(error != 0, "setVsyncEnabled: Failed to set vsync on HWC1 (%d)",
+ error);
+
+ mVsyncEnabled = enable;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::validate(uint32_t* outNumTypes,
+ uint32_t* outNumRequests) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!mChanges) {
+ if (!mDevice.prepareAllDisplays()) {
+ return Error::BadDisplay;
+ }
+ } else {
+ ALOGE("Validate was called more than once!");
+ }
+
+ *outNumTypes = mChanges->getNumTypes();
+ *outNumRequests = mChanges->getNumLayerRequests();
+ ALOGV("[%" PRIu64 "] validate --> %u types, %u requests", mId, *outNumTypes,
+ *outNumRequests);
+ for (auto request : mChanges->getTypeChanges()) {
+ ALOGV("Layer %" PRIu64 " --> %s", request.first,
+ to_string(request.second).c_str());
+ }
+ return *outNumTypes > 0 ? Error::HasChanges : Error::None;
+}
+
+Error HWC2On1Adapter::Display::updateLayerZ(hwc2_layer_t layerId, uint32_t z) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ const auto mapLayer = mDevice.mLayers.find(layerId);
+ if (mapLayer == mDevice.mLayers.end()) {
+ ALOGE("[%" PRIu64 "] updateLayerZ failed to find layer", mId);
+ return Error::BadLayer;
+ }
+
+ const auto layer = mapLayer->second;
+ const auto zRange = mLayers.equal_range(layer);
+ bool layerOnDisplay = false;
+ for (auto current = zRange.first; current != zRange.second; ++current) {
+ if (**current == *layer) {
+ if ((*current)->getZ() == z) {
+ // Don't change anything if the Z hasn't changed
+ return Error::None;
+ }
+ current = mLayers.erase(current);
+ layerOnDisplay = true;
+ break;
+ }
+ }
+
+ if (!layerOnDisplay) {
+ ALOGE("[%" PRIu64 "] updateLayerZ failed to find layer on display",
+ mId);
+ return Error::BadLayer;
+ }
+
+ layer->setZ(z);
+ mLayers.emplace(std::move(layer));
+ markGeometryChanged();
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getClientTargetSupport(uint32_t width, uint32_t height,
+ int32_t format, int32_t dataspace){
+ if (mActiveConfig == nullptr) {
+ return Error::Unsupported;
+ }
+
+ if (width == mActiveConfig->getAttribute(Attribute::Width) &&
+ height == mActiveConfig->getAttribute(Attribute::Height) &&
+ format == HAL_PIXEL_FORMAT_RGBA_8888 &&
+ dataspace == HAL_DATASPACE_UNKNOWN) {
+ return Error::None;
+ }
+
+ return Error::Unsupported;
+}
+
+static constexpr uint32_t ATTRIBUTES_WITH_COLOR[] = {
+ HWC_DISPLAY_VSYNC_PERIOD,
+ HWC_DISPLAY_WIDTH,
+ HWC_DISPLAY_HEIGHT,
+ HWC_DISPLAY_DPI_X,
+ HWC_DISPLAY_DPI_Y,
+ HWC_DISPLAY_COLOR_TRANSFORM,
+ HWC_DISPLAY_NO_ATTRIBUTE,
+};
+
+static constexpr uint32_t ATTRIBUTES_WITHOUT_COLOR[] = {
+ HWC_DISPLAY_VSYNC_PERIOD,
+ HWC_DISPLAY_WIDTH,
+ HWC_DISPLAY_HEIGHT,
+ HWC_DISPLAY_DPI_X,
+ HWC_DISPLAY_DPI_Y,
+ HWC_DISPLAY_NO_ATTRIBUTE,
+};
+
+static constexpr size_t NUM_ATTRIBUTES_WITH_COLOR =
+ sizeof(ATTRIBUTES_WITH_COLOR) / sizeof(uint32_t);
+static_assert(sizeof(ATTRIBUTES_WITH_COLOR) > sizeof(ATTRIBUTES_WITHOUT_COLOR),
+ "Attribute tables have unexpected sizes");
+
+static constexpr uint32_t ATTRIBUTE_MAP_WITH_COLOR[] = {
+ 6, // HWC_DISPLAY_NO_ATTRIBUTE = 0
+ 0, // HWC_DISPLAY_VSYNC_PERIOD = 1,
+ 1, // HWC_DISPLAY_WIDTH = 2,
+ 2, // HWC_DISPLAY_HEIGHT = 3,
+ 3, // HWC_DISPLAY_DPI_X = 4,
+ 4, // HWC_DISPLAY_DPI_Y = 5,
+ 5, // HWC_DISPLAY_COLOR_TRANSFORM = 6,
+};
+
+static constexpr uint32_t ATTRIBUTE_MAP_WITHOUT_COLOR[] = {
+ 5, // HWC_DISPLAY_NO_ATTRIBUTE = 0
+ 0, // HWC_DISPLAY_VSYNC_PERIOD = 1,
+ 1, // HWC_DISPLAY_WIDTH = 2,
+ 2, // HWC_DISPLAY_HEIGHT = 3,
+ 3, // HWC_DISPLAY_DPI_X = 4,
+ 4, // HWC_DISPLAY_DPI_Y = 5,
+};
+
+template <uint32_t attribute>
+static constexpr bool attributesMatch()
+{
+ bool match = (attribute ==
+ ATTRIBUTES_WITH_COLOR[ATTRIBUTE_MAP_WITH_COLOR[attribute]]);
+ if (attribute == HWC_DISPLAY_COLOR_TRANSFORM) {
+ return match;
+ }
+
+ return match && (attribute ==
+ ATTRIBUTES_WITHOUT_COLOR[ATTRIBUTE_MAP_WITHOUT_COLOR[attribute]]);
+}
+static_assert(attributesMatch<HWC_DISPLAY_VSYNC_PERIOD>(),
+ "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_WIDTH>(), "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_HEIGHT>(), "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_DPI_X>(), "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_DPI_Y>(), "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_COLOR_TRANSFORM>(),
+ "Tables out of sync");
+
+void HWC2On1Adapter::Display::populateConfigs() {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ ALOGV("[%" PRIu64 "] populateConfigs", mId);
+
+ if (mHwc1Id == -1) {
+ ALOGE("populateConfigs: HWC1 ID not set");
+ return;
+ }
+
+ const size_t MAX_NUM_CONFIGS = 128;
+ uint32_t configs[MAX_NUM_CONFIGS] = {};
+ size_t numConfigs = MAX_NUM_CONFIGS;
+ mDevice.mHwc1Device->getDisplayConfigs(mDevice.mHwc1Device, mHwc1Id,
+ configs, &numConfigs);
+
+ for (size_t c = 0; c < numConfigs; ++c) {
+ uint32_t hwc1ConfigId = configs[c];
+ auto newConfig = std::make_shared<Config>(*this);
+
+ int32_t values[NUM_ATTRIBUTES_WITH_COLOR] = {};
+ bool hasColor = true;
+ auto result = mDevice.mHwc1Device->getDisplayAttributes(
+ mDevice.mHwc1Device, mHwc1Id, hwc1ConfigId,
+ ATTRIBUTES_WITH_COLOR, values);
+ if (result != 0) {
+ mDevice.mHwc1Device->getDisplayAttributes(mDevice.mHwc1Device,
+ mHwc1Id, hwc1ConfigId, ATTRIBUTES_WITHOUT_COLOR, values);
+ hasColor = false;
+ }
+
+ auto attributeMap = hasColor ?
+ ATTRIBUTE_MAP_WITH_COLOR : ATTRIBUTE_MAP_WITHOUT_COLOR;
+
+ newConfig->setAttribute(Attribute::VsyncPeriod,
+ values[attributeMap[HWC_DISPLAY_VSYNC_PERIOD]]);
+ newConfig->setAttribute(Attribute::Width,
+ values[attributeMap[HWC_DISPLAY_WIDTH]]);
+ newConfig->setAttribute(Attribute::Height,
+ values[attributeMap[HWC_DISPLAY_HEIGHT]]);
+ newConfig->setAttribute(Attribute::DpiX,
+ values[attributeMap[HWC_DISPLAY_DPI_X]]);
+ newConfig->setAttribute(Attribute::DpiY,
+ values[attributeMap[HWC_DISPLAY_DPI_Y]]);
+ if (hasColor) {
+ // In HWC1, color modes are referred to as color transforms. To avoid confusion with
+ // the HWC2 concept of color transforms, we internally refer to them as color modes for
+ // both HWC1 and 2.
+ newConfig->setAttribute(ColorMode,
+ values[attributeMap[HWC_DISPLAY_COLOR_TRANSFORM]]);
+ }
+
+ // We can only do this after attempting to read the color mode
+ newConfig->setHwc1Id(hwc1ConfigId);
+
+ for (auto& existingConfig : mConfigs) {
+ if (existingConfig->merge(*newConfig)) {
+ ALOGV("Merged config %d with existing config %u: %s",
+ hwc1ConfigId, existingConfig->getId(),
+ existingConfig->toString().c_str());
+ newConfig.reset();
+ break;
+ }
+ }
+
+ // If it wasn't merged with any existing config, add it to the end
+ if (newConfig) {
+ newConfig->setId(static_cast<hwc2_config_t>(mConfigs.size()));
+ ALOGV("Found new config %u: %s", newConfig->getId(),
+ newConfig->toString().c_str());
+ mConfigs.emplace_back(std::move(newConfig));
+ }
+ }
+
+ initializeActiveConfig();
+ populateColorModes();
+}
+
+void HWC2On1Adapter::Display::populateConfigs(uint32_t width, uint32_t height) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ mConfigs.emplace_back(std::make_shared<Config>(*this));
+ auto& config = mConfigs[0];
+
+ config->setAttribute(Attribute::Width, static_cast<int32_t>(width));
+ config->setAttribute(Attribute::Height, static_cast<int32_t>(height));
+ config->setHwc1Id(0);
+ config->setId(0);
+ mActiveConfig = config;
+}
+
+bool HWC2On1Adapter::Display::prepare() {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ // Only prepare display contents for displays HWC1 knows about
+ if (mHwc1Id == -1) {
+ return true;
+ }
+
+ // It doesn't make sense to prepare a display for which there is no active
+ // config, so return early
+ if (!mActiveConfig) {
+ ALOGE("[%" PRIu64 "] Attempted to prepare, but no config active", mId);
+ return false;
+ }
+
+ allocateRequestedContents();
+ assignHwc1LayerIds();
+
+ mHwc1RequestedContents->retireFenceFd = -1;
+ mHwc1RequestedContents->flags = 0;
+ if (mGeometryChanged) {
+ mHwc1RequestedContents->flags |= HWC_GEOMETRY_CHANGED;
+ }
+ mHwc1RequestedContents->outbuf = mOutputBuffer.getBuffer();
+ mHwc1RequestedContents->outbufAcquireFenceFd = mOutputBuffer.getFence();
+
+ // +1 is for framebuffer target layer.
+ mHwc1RequestedContents->numHwLayers = mLayers.size() + 1;
+ for (auto& layer : mLayers) {
+ auto& hwc1Layer = mHwc1RequestedContents->hwLayers[layer->getHwc1Id()];
+ hwc1Layer.releaseFenceFd = -1;
+ hwc1Layer.acquireFenceFd = -1;
+ ALOGV("Applying states for layer %" PRIu64 " ", layer->getId());
+ layer->applyState(hwc1Layer);
+ }
+
+ prepareFramebufferTarget();
+
+ resetGeometryMarker();
+
+ return true;
+}
+
+void HWC2On1Adapter::Display::generateChanges() {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ mChanges.reset(new Changes);
+
+ size_t numLayers = mHwc1RequestedContents->numHwLayers;
+ for (size_t hwc1Id = 0; hwc1Id < numLayers; ++hwc1Id) {
+ const auto& receivedLayer = mHwc1RequestedContents->hwLayers[hwc1Id];
+ if (mHwc1LayerMap.count(hwc1Id) == 0) {
+ ALOGE_IF(receivedLayer.compositionType != HWC_FRAMEBUFFER_TARGET,
+ "generateChanges: HWC1 layer %zd doesn't have a"
+ " matching HWC2 layer, and isn't the framebuffer target",
+ hwc1Id);
+ continue;
+ }
+
+ Layer& layer = *mHwc1LayerMap[hwc1Id];
+ updateTypeChanges(receivedLayer, layer);
+ updateLayerRequests(receivedLayer, layer);
+ }
+}
+
+bool HWC2On1Adapter::Display::hasChanges() const {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+ return mChanges != nullptr;
+}
+
+Error HWC2On1Adapter::Display::set(hwc_display_contents_1& hwcContents) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!mChanges || (mChanges->getNumTypes() > 0)) {
+ ALOGE("[%" PRIu64 "] set failed: not validated", mId);
+ return Error::NotValidated;
+ }
+
+ // Set up the client/framebuffer target
+ auto numLayers = hwcContents.numHwLayers;
+
+ // Close acquire fences on FRAMEBUFFER layers, since they will not be used
+ // by HWC
+ for (size_t l = 0; l < numLayers - 1; ++l) {
+ auto& layer = hwcContents.hwLayers[l];
+ if (layer.compositionType == HWC_FRAMEBUFFER) {
+ ALOGV("Closing fence %d for layer %zd", layer.acquireFenceFd, l);
+ close(layer.acquireFenceFd);
+ layer.acquireFenceFd = -1;
+ }
+ }
+
+ auto& clientTargetLayer = hwcContents.hwLayers[numLayers - 1];
+ if (clientTargetLayer.compositionType == HWC_FRAMEBUFFER_TARGET) {
+ clientTargetLayer.handle = mClientTarget.getBuffer();
+ clientTargetLayer.acquireFenceFd = mClientTarget.getFence();
+ } else {
+ ALOGE("[%" PRIu64 "] set: last HWC layer wasn't FRAMEBUFFER_TARGET",
+ mId);
+ }
+
+ mChanges.reset();
+
+ return Error::None;
+}
+
+void HWC2On1Adapter::Display::addRetireFence(int fenceFd) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+ mRetireFence.add(fenceFd);
+}
+
+void HWC2On1Adapter::Display::addReleaseFences(
+ const hwc_display_contents_1_t& hwcContents) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ size_t numLayers = hwcContents.numHwLayers;
+ for (size_t hwc1Id = 0; hwc1Id < numLayers; ++hwc1Id) {
+ const auto& receivedLayer = hwcContents.hwLayers[hwc1Id];
+ if (mHwc1LayerMap.count(hwc1Id) == 0) {
+ if (receivedLayer.compositionType != HWC_FRAMEBUFFER_TARGET) {
+ ALOGE("addReleaseFences: HWC1 layer %zd doesn't have a"
+ " matching HWC2 layer, and isn't the framebuffer"
+ " target", hwc1Id);
+ }
+ // Close the framebuffer target release fence since we will use the
+ // display retire fence instead
+ if (receivedLayer.releaseFenceFd != -1) {
+ close(receivedLayer.releaseFenceFd);
+ }
+ continue;
+ }
+
+ Layer& layer = *mHwc1LayerMap[hwc1Id];
+ ALOGV("Adding release fence %d to layer %" PRIu64,
+ receivedLayer.releaseFenceFd, layer.getId());
+ layer.addReleaseFence(receivedLayer.releaseFenceFd);
+ }
+}
+
+bool HWC2On1Adapter::Display::hasColorTransform() const {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+ return mHasColorTransform;
+}
+
+static std::string hwc1CompositionString(int32_t type) {
+ switch (type) {
+ case HWC_FRAMEBUFFER: return "Framebuffer";
+ case HWC_OVERLAY: return "Overlay";
+ case HWC_BACKGROUND: return "Background";
+ case HWC_FRAMEBUFFER_TARGET: return "FramebufferTarget";
+ case HWC_SIDEBAND: return "Sideband";
+ case HWC_CURSOR_OVERLAY: return "CursorOverlay";
+ default:
+ return std::string("Unknown (") + std::to_string(type) + ")";
+ }
+}
+
+static std::string hwc1TransformString(int32_t transform) {
+ switch (transform) {
+ case 0: return "None";
+ case HWC_TRANSFORM_FLIP_H: return "FlipH";
+ case HWC_TRANSFORM_FLIP_V: return "FlipV";
+ case HWC_TRANSFORM_ROT_90: return "Rotate90";
+ case HWC_TRANSFORM_ROT_180: return "Rotate180";
+ case HWC_TRANSFORM_ROT_270: return "Rotate270";
+ case HWC_TRANSFORM_FLIP_H_ROT_90: return "FlipHRotate90";
+ case HWC_TRANSFORM_FLIP_V_ROT_90: return "FlipVRotate90";
+ default:
+ return std::string("Unknown (") + std::to_string(transform) + ")";
+ }
+}
+
+static std::string hwc1BlendModeString(int32_t mode) {
+ switch (mode) {
+ case HWC_BLENDING_NONE: return "None";
+ case HWC_BLENDING_PREMULT: return "Premultiplied";
+ case HWC_BLENDING_COVERAGE: return "Coverage";
+ default:
+ return std::string("Unknown (") + std::to_string(mode) + ")";
+ }
+}
+
+static std::string rectString(hwc_rect_t rect) {
+ std::stringstream output;
+ output << "[" << rect.left << ", " << rect.top << ", ";
+ output << rect.right << ", " << rect.bottom << "]";
+ return output.str();
+}
+
+static std::string approximateFloatString(float f) {
+ if (static_cast<int32_t>(f) == f) {
+ return std::to_string(static_cast<int32_t>(f));
+ }
+ int32_t truncated = static_cast<int32_t>(f * 10);
+ bool approximate = (static_cast<float>(truncated) != f * 10);
+ const size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ auto bytesWritten = snprintf(buffer, BUFFER_SIZE,
+ "%s%.1f", approximate ? "~" : "", f);
+ return std::string(buffer, bytesWritten);
+}
+
+static std::string frectString(hwc_frect_t frect) {
+ std::stringstream output;
+ output << "[" << approximateFloatString(frect.left) << ", ";
+ output << approximateFloatString(frect.top) << ", ";
+ output << approximateFloatString(frect.right) << ", ";
+ output << approximateFloatString(frect.bottom) << "]";
+ return output.str();
+}
+
+static std::string colorString(hwc_color_t color) {
+ std::stringstream output;
+ output << "RGBA [";
+ output << static_cast<int32_t>(color.r) << ", ";
+ output << static_cast<int32_t>(color.g) << ", ";
+ output << static_cast<int32_t>(color.b) << ", ";
+ output << static_cast<int32_t>(color.a) << "]";
+ return output.str();
+}
+
+static std::string alphaString(float f) {
+ const size_t BUFFER_SIZE = 8;
+ char buffer[BUFFER_SIZE] = {};
+ auto bytesWritten = snprintf(buffer, BUFFER_SIZE, "%.3f", f);
+ return std::string(buffer, bytesWritten);
+}
+
+static std::string to_string(const hwc_layer_1_t& hwcLayer,
+ int32_t hwc1MinorVersion) {
+ const char* fill = " ";
+
+ std::stringstream output;
+
+ output << " Composition: " <<
+ hwc1CompositionString(hwcLayer.compositionType);
+
+ if (hwcLayer.compositionType == HWC_BACKGROUND) {
+ output << " Color: " << colorString(hwcLayer.backgroundColor) << '\n';
+ } else if (hwcLayer.compositionType == HWC_SIDEBAND) {
+ output << " Stream: " << hwcLayer.sidebandStream << '\n';
+ } else {
+ output << " Buffer: " << hwcLayer.handle << "/" <<
+ hwcLayer.acquireFenceFd << '\n';
+ }
+
+ output << fill << "Display frame: " << rectString(hwcLayer.displayFrame) <<
+ '\n';
+
+ output << fill << "Source crop: ";
+ if (hwc1MinorVersion >= 3) {
+ output << frectString(hwcLayer.sourceCropf) << '\n';
+ } else {
+ output << rectString(hwcLayer.sourceCropi) << '\n';
+ }
+
+ output << fill << "Transform: " << hwc1TransformString(hwcLayer.transform);
+ output << " Blend mode: " << hwc1BlendModeString(hwcLayer.blending);
+ if (hwcLayer.planeAlpha != 0xFF) {
+ output << " Alpha: " << alphaString(hwcLayer.planeAlpha / 255.0f);
+ }
+ output << '\n';
+
+ if (hwcLayer.hints != 0) {
+ output << fill << "Hints:";
+ if ((hwcLayer.hints & HWC_HINT_TRIPLE_BUFFER) != 0) {
+ output << " TripleBuffer";
+ }
+ if ((hwcLayer.hints & HWC_HINT_CLEAR_FB) != 0) {
+ output << " ClearFB";
+ }
+ output << '\n';
+ }
+
+ if (hwcLayer.flags != 0) {
+ output << fill << "Flags:";
+ if ((hwcLayer.flags & HWC_SKIP_LAYER) != 0) {
+ output << " SkipLayer";
+ }
+ if ((hwcLayer.flags & HWC_IS_CURSOR_LAYER) != 0) {
+ output << " IsCursorLayer";
+ }
+ output << '\n';
+ }
+
+ return output.str();
+}
+
+static std::string to_string(const hwc_display_contents_1_t& hwcContents,
+ int32_t hwc1MinorVersion) {
+ const char* fill = " ";
+
+ std::stringstream output;
+ output << fill << "Geometry changed: " <<
+ ((hwcContents.flags & HWC_GEOMETRY_CHANGED) != 0 ? "Y\n" : "N\n");
+
+ output << fill << hwcContents.numHwLayers << " Layer" <<
+ ((hwcContents.numHwLayers == 1) ? "\n" : "s\n");
+ for (size_t layer = 0; layer < hwcContents.numHwLayers; ++layer) {
+ output << fill << " Layer " << layer;
+ output << to_string(hwcContents.hwLayers[layer], hwc1MinorVersion);
+ }
+
+ if (hwcContents.outbuf != nullptr) {
+ output << fill << "Output buffer: " << hwcContents.outbuf << "/" <<
+ hwcContents.outbufAcquireFenceFd << '\n';
+ }
+
+ return output.str();
+}
+
+std::string HWC2On1Adapter::Display::dump() const {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ std::stringstream output;
+
+ output << " Display " << mId << ": ";
+ output << to_string(mType) << " ";
+ output << "HWC1 ID: " << mHwc1Id << " ";
+ output << "Power mode: " << to_string(mPowerMode) << " ";
+ output << "Vsync: " << to_string(mVsyncEnabled) << '\n';
+
+ output << " Color modes [active]:";
+ for (const auto& mode : mColorModes) {
+ if (mode == mActiveColorMode) {
+ output << " [" << mode << ']';
+ } else {
+ output << " " << mode;
+ }
+ }
+ output << '\n';
+
+ output << " " << mConfigs.size() << " Config" <<
+ (mConfigs.size() == 1 ? "" : "s") << " (* active)\n";
+ for (const auto& config : mConfigs) {
+ output << (config == mActiveConfig ? " * " : " ");
+ output << config->toString(true) << '\n';
+ }
+
+ output << " " << mLayers.size() << " Layer" <<
+ (mLayers.size() == 1 ? "" : "s") << '\n';
+ for (const auto& layer : mLayers) {
+ output << layer->dump();
+ }
+
+ output << " Client target: " << mClientTarget.getBuffer() << '\n';
+
+ if (mOutputBuffer.getBuffer() != nullptr) {
+ output << " Output buffer: " << mOutputBuffer.getBuffer() << '\n';
+ }
+
+ if (mHwc1RequestedContents) {
+ output << " Last requested HWC1 state\n";
+ output << to_string(*mHwc1RequestedContents, mDevice.mHwc1MinorVersion);
+ }
+
+ return output.str();
+}
+
+hwc_rect_t* HWC2On1Adapter::Display::GetRects(size_t numRects) {
+ if (numRects == 0) {
+ return nullptr;
+ }
+
+ if (numRects > mNumAvailableRects) {
+ // This should NEVER happen since we calculated how many rects the
+ // display would need.
+ ALOGE("Rect allocation failure! SF is likely to crash soon!");
+ return nullptr;
+
+ }
+ hwc_rect_t* rects = mNextAvailableRect;
+ mNextAvailableRect += numRects;
+ mNumAvailableRects -= numRects;
+ return rects;
+}
+
+hwc_display_contents_1* HWC2On1Adapter::Display::getDisplayContents() {
+ return mHwc1RequestedContents.get();
+}
+
+void HWC2On1Adapter::Display::Config::setAttribute(HWC2::Attribute attribute,
+ int32_t value) {
+ mAttributes[attribute] = value;
+}
+
+int32_t HWC2On1Adapter::Display::Config::getAttribute(Attribute attribute) const {
+ if (mAttributes.count(attribute) == 0) {
+ return -1;
+ }
+ return mAttributes.at(attribute);
+}
+
+void HWC2On1Adapter::Display::Config::setHwc1Id(uint32_t id) {
+ android_color_mode_t colorMode = static_cast<android_color_mode_t>(getAttribute(ColorMode));
+ mHwc1Ids.emplace(colorMode, id);
+}
+
+bool HWC2On1Adapter::Display::Config::hasHwc1Id(uint32_t id) const {
+ for (const auto& idPair : mHwc1Ids) {
+ if (id == idPair.second) {
+ return true;
+ }
+ }
+ return false;
+}
+
+Error HWC2On1Adapter::Display::Config::getColorModeForHwc1Id(
+ uint32_t id, android_color_mode_t* outMode) const {
+ for (const auto& idPair : mHwc1Ids) {
+ if (id == idPair.second) {
+ *outMode = idPair.first;
+ return Error::None;
+ }
+ }
+ ALOGE("Unable to find color mode for HWC ID %" PRIu32 " on config %u", id, mId);
+ return Error::BadParameter;
+}
+
+Error HWC2On1Adapter::Display::Config::getHwc1IdForColorMode(android_color_mode_t mode,
+ uint32_t* outId) const {
+ for (const auto& idPair : mHwc1Ids) {
+ if (mode == idPair.first) {
+ *outId = idPair.second;
+ return Error::None;
+ }
+ }
+ ALOGE("Unable to find HWC1 ID for color mode %d on config %u", mode, mId);
+ return Error::BadParameter;
+}
+
+bool HWC2On1Adapter::Display::Config::merge(const Config& other) {
+ auto attributes = {HWC2::Attribute::Width, HWC2::Attribute::Height,
+ HWC2::Attribute::VsyncPeriod, HWC2::Attribute::DpiX,
+ HWC2::Attribute::DpiY};
+ for (auto attribute : attributes) {
+ if (getAttribute(attribute) != other.getAttribute(attribute)) {
+ return false;
+ }
+ }
+ android_color_mode_t otherColorMode =
+ static_cast<android_color_mode_t>(other.getAttribute(ColorMode));
+ if (mHwc1Ids.count(otherColorMode) != 0) {
+ ALOGE("Attempted to merge two configs (%u and %u) which appear to be "
+ "identical", mHwc1Ids.at(otherColorMode),
+ other.mHwc1Ids.at(otherColorMode));
+ return false;
+ }
+ mHwc1Ids.emplace(otherColorMode,
+ other.mHwc1Ids.at(otherColorMode));
+ return true;
+}
+
+std::set<android_color_mode_t> HWC2On1Adapter::Display::Config::getColorModes() const {
+ std::set<android_color_mode_t> colorModes;
+ for (const auto& idPair : mHwc1Ids) {
+ colorModes.emplace(idPair.first);
+ }
+ return colorModes;
+}
+
+std::string HWC2On1Adapter::Display::Config::toString(bool splitLine) const {
+ std::string output;
+
+ const size_t BUFFER_SIZE = 100;
+ char buffer[BUFFER_SIZE] = {};
+ auto writtenBytes = snprintf(buffer, BUFFER_SIZE,
+ "%u x %u", mAttributes.at(HWC2::Attribute::Width),
+ mAttributes.at(HWC2::Attribute::Height));
+ output.append(buffer, writtenBytes);
+
+ if (mAttributes.count(HWC2::Attribute::VsyncPeriod) != 0) {
+ std::memset(buffer, 0, BUFFER_SIZE);
+ writtenBytes = snprintf(buffer, BUFFER_SIZE, " @ %.1f Hz",
+ 1e9 / mAttributes.at(HWC2::Attribute::VsyncPeriod));
+ output.append(buffer, writtenBytes);
+ }
+
+ if (mAttributes.count(HWC2::Attribute::DpiX) != 0 &&
+ mAttributes.at(HWC2::Attribute::DpiX) != -1) {
+ std::memset(buffer, 0, BUFFER_SIZE);
+ writtenBytes = snprintf(buffer, BUFFER_SIZE,
+ ", DPI: %.1f x %.1f",
+ mAttributes.at(HWC2::Attribute::DpiX) / 1000.0f,
+ mAttributes.at(HWC2::Attribute::DpiY) / 1000.0f);
+ output.append(buffer, writtenBytes);
+ }
+
+ std::memset(buffer, 0, BUFFER_SIZE);
+ if (splitLine) {
+ writtenBytes = snprintf(buffer, BUFFER_SIZE,
+ "\n HWC1 ID/Color transform:");
+ } else {
+ writtenBytes = snprintf(buffer, BUFFER_SIZE,
+ ", HWC1 ID/Color transform:");
+ }
+ output.append(buffer, writtenBytes);
+
+
+ for (const auto& id : mHwc1Ids) {
+ android_color_mode_t colorMode = id.first;
+ uint32_t hwc1Id = id.second;
+ std::memset(buffer, 0, BUFFER_SIZE);
+ if (colorMode == mDisplay.mActiveColorMode) {
+ writtenBytes = snprintf(buffer, BUFFER_SIZE, " [%u/%d]", hwc1Id,
+ colorMode);
+ } else {
+ writtenBytes = snprintf(buffer, BUFFER_SIZE, " %u/%d", hwc1Id,
+ colorMode);
+ }
+ output.append(buffer, writtenBytes);
+ }
+
+ return output;
+}
+
+std::shared_ptr<const HWC2On1Adapter::Display::Config>
+ HWC2On1Adapter::Display::getConfig(hwc2_config_t configId) const {
+ if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) {
+ return nullptr;
+ }
+ return mConfigs[configId];
+}
+
+void HWC2On1Adapter::Display::populateColorModes() {
+ mColorModes = mConfigs[0]->getColorModes();
+ for (const auto& config : mConfigs) {
+ std::set<android_color_mode_t> intersection;
+ auto configModes = config->getColorModes();
+ std::set_intersection(mColorModes.cbegin(), mColorModes.cend(),
+ configModes.cbegin(), configModes.cend(),
+ std::inserter(intersection, intersection.begin()));
+ std::swap(intersection, mColorModes);
+ }
+}
+
+void HWC2On1Adapter::Display::initializeActiveConfig() {
+ if (mDevice.mHwc1Device->getActiveConfig == nullptr) {
+ ALOGV("getActiveConfig is null, choosing config 0");
+ mActiveConfig = mConfigs[0];
+ mActiveColorMode = HAL_COLOR_MODE_NATIVE;
+ return;
+ }
+
+ auto activeConfig = mDevice.mHwc1Device->getActiveConfig(
+ mDevice.mHwc1Device, mHwc1Id);
+
+ // Some devices startup without an activeConfig:
+ // We need to set one ourselves.
+ if (activeConfig == HWC_ERROR) {
+ ALOGV("There is no active configuration: Picking the first one: 0.");
+ const int defaultIndex = 0;
+ mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device, mHwc1Id, defaultIndex);
+ activeConfig = defaultIndex;
+ }
+
+ for (const auto& config : mConfigs) {
+ if (config->hasHwc1Id(activeConfig)) {
+ ALOGE("Setting active config to %d for HWC1 config %u", config->getId(), activeConfig);
+ mActiveConfig = config;
+ if (config->getColorModeForHwc1Id(activeConfig, &mActiveColorMode) != Error::None) {
+ // This should never happen since we checked for the config's presence before
+ // setting it as active.
+ ALOGE("Unable to find color mode for active HWC1 config %d", config->getId());
+ mActiveColorMode = HAL_COLOR_MODE_NATIVE;
+ }
+ break;
+ }
+ }
+ if (!mActiveConfig) {
+ ALOGV("Unable to find active HWC1 config %u, defaulting to "
+ "config 0", activeConfig);
+ mActiveConfig = mConfigs[0];
+ mActiveColorMode = HAL_COLOR_MODE_NATIVE;
+ }
+
+
+
+
+}
+
+void HWC2On1Adapter::Display::allocateRequestedContents() {
+ // What needs to be allocated:
+ // 1 hwc_display_contents_1_t
+ // 1 hwc_layer_1_t for each layer
+ // 1 hwc_rect_t for each layer's surfaceDamage
+ // 1 hwc_rect_t for each layer's visibleRegion
+ // 1 hwc_layer_1_t for the framebuffer
+ // 1 hwc_rect_t for the framebuffer's visibleRegion
+
+ // Count # of surfaceDamage
+ size_t numSurfaceDamages = 0;
+ for (const auto& layer : mLayers) {
+ numSurfaceDamages += layer->getNumSurfaceDamages();
+ }
+
+ // Count # of visibleRegions (start at 1 for mandatory framebuffer target
+ // region)
+ size_t numVisibleRegion = 1;
+ for (const auto& layer : mLayers) {
+ numVisibleRegion += layer->getNumVisibleRegions();
+ }
+
+ size_t numRects = numVisibleRegion + numSurfaceDamages;
+ auto numLayers = mLayers.size() + 1;
+ size_t size = sizeof(hwc_display_contents_1_t) +
+ sizeof(hwc_layer_1_t) * numLayers +
+ sizeof(hwc_rect_t) * numRects;
+ auto contents = static_cast<hwc_display_contents_1_t*>(std::calloc(size, 1));
+ mHwc1RequestedContents.reset(contents);
+ mNextAvailableRect = reinterpret_cast<hwc_rect_t*>(&contents->hwLayers[numLayers]);
+ mNumAvailableRects = numRects;
+}
+
+void HWC2On1Adapter::Display::assignHwc1LayerIds() {
+ mHwc1LayerMap.clear();
+ size_t nextHwc1Id = 0;
+ for (auto& layer : mLayers) {
+ mHwc1LayerMap[nextHwc1Id] = layer;
+ layer->setHwc1Id(nextHwc1Id++);
+ }
+}
+
+void HWC2On1Adapter::Display::updateTypeChanges(const hwc_layer_1_t& hwc1Layer,
+ const Layer& layer) {
+ auto layerId = layer.getId();
+ switch (hwc1Layer.compositionType) {
+ case HWC_FRAMEBUFFER:
+ if (layer.getCompositionType() != Composition::Client) {
+ mChanges->addTypeChange(layerId, Composition::Client);
+ }
+ break;
+ case HWC_OVERLAY:
+ if (layer.getCompositionType() != Composition::Device) {
+ mChanges->addTypeChange(layerId, Composition::Device);
+ }
+ break;
+ case HWC_BACKGROUND:
+ ALOGE_IF(layer.getCompositionType() != Composition::SolidColor,
+ "updateTypeChanges: HWC1 requested BACKGROUND, but HWC2"
+ " wasn't expecting SolidColor");
+ break;
+ case HWC_FRAMEBUFFER_TARGET:
+ // Do nothing, since it shouldn't be modified by HWC1
+ break;
+ case HWC_SIDEBAND:
+ ALOGE_IF(layer.getCompositionType() != Composition::Sideband,
+ "updateTypeChanges: HWC1 requested SIDEBAND, but HWC2"
+ " wasn't expecting Sideband");
+ break;
+ case HWC_CURSOR_OVERLAY:
+ ALOGE_IF(layer.getCompositionType() != Composition::Cursor,
+ "updateTypeChanges: HWC1 requested CURSOR_OVERLAY, but"
+ " HWC2 wasn't expecting Cursor");
+ break;
+ }
+}
+
+void HWC2On1Adapter::Display::updateLayerRequests(
+ const hwc_layer_1_t& hwc1Layer, const Layer& layer) {
+ if ((hwc1Layer.hints & HWC_HINT_CLEAR_FB) != 0) {
+ mChanges->addLayerRequest(layer.getId(),
+ LayerRequest::ClearClientTarget);
+ }
+}
+
+void HWC2On1Adapter::Display::prepareFramebufferTarget() {
+ // We check that mActiveConfig is valid in Display::prepare
+ int32_t width = mActiveConfig->getAttribute(Attribute::Width);
+ int32_t height = mActiveConfig->getAttribute(Attribute::Height);
+
+ auto& hwc1Target = mHwc1RequestedContents->hwLayers[mLayers.size()];
+ hwc1Target.compositionType = HWC_FRAMEBUFFER_TARGET;
+ hwc1Target.releaseFenceFd = -1;
+ hwc1Target.hints = 0;
+ hwc1Target.flags = 0;
+ hwc1Target.transform = 0;
+ hwc1Target.blending = HWC_BLENDING_PREMULT;
+ if (mDevice.getHwc1MinorVersion() < 3) {
+ hwc1Target.sourceCropi = {0, 0, width, height};
+ } else {
+ hwc1Target.sourceCropf = {0.0f, 0.0f, static_cast<float>(width),
+ static_cast<float>(height)};
+ }
+ hwc1Target.displayFrame = {0, 0, width, height};
+ hwc1Target.planeAlpha = 255;
+
+ hwc1Target.visibleRegionScreen.numRects = 1;
+ hwc_rect_t* rects = GetRects(1);
+ rects[0].left = 0;
+ rects[0].top = 0;
+ rects[0].right = width;
+ rects[0].bottom = height;
+ hwc1Target.visibleRegionScreen.rects = rects;
+
+ // We will set this to the correct value in set
+ hwc1Target.acquireFenceFd = -1;
+}
+
+// Layer functions
+
+std::atomic<hwc2_layer_t> HWC2On1Adapter::Layer::sNextId(1);
+
+HWC2On1Adapter::Layer::Layer(Display& display)
+ : mId(sNextId++),
+ mDisplay(display),
+ mBuffer(),
+ mSurfaceDamage(),
+ mBlendMode(BlendMode::None),
+ mColor({0, 0, 0, 0}),
+ mCompositionType(Composition::Invalid),
+ mDisplayFrame({0, 0, -1, -1}),
+ mPlaneAlpha(0.0f),
+ mSidebandStream(nullptr),
+ mSourceCrop({0.0f, 0.0f, -1.0f, -1.0f}),
+ mTransform(Transform::None),
+ mVisibleRegion(),
+ mZ(0),
+ mReleaseFence(),
+ mHwc1Id(0),
+ mHasUnsupportedPlaneAlpha(false) {}
+
+bool HWC2On1Adapter::SortLayersByZ::operator()(
+ const std::shared_ptr<Layer>& lhs, const std::shared_ptr<Layer>& rhs) {
+ return lhs->getZ() < rhs->getZ();
+}
+
+Error HWC2On1Adapter::Layer::setBuffer(buffer_handle_t buffer,
+ int32_t acquireFence) {
+ ALOGV("Setting acquireFence to %d for layer %" PRIu64, acquireFence, mId);
+ mBuffer.setBuffer(buffer);
+ mBuffer.setFence(acquireFence);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setCursorPosition(int32_t x, int32_t y) {
+ if (mCompositionType != Composition::Cursor) {
+ return Error::BadLayer;
+ }
+
+ if (mDisplay.hasChanges()) {
+ return Error::NotValidated;
+ }
+
+ auto displayId = mDisplay.getHwc1Id();
+ auto hwc1Device = mDisplay.getDevice().getHwc1Device();
+ hwc1Device->setCursorPositionAsync(hwc1Device, displayId, x, y);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setSurfaceDamage(hwc_region_t damage) {
+ // HWC1 supports surface damage starting only with version 1.5.
+ if (mDisplay.getDevice().mHwc1MinorVersion < 5) {
+ return Error::None;
+ }
+ mSurfaceDamage.resize(damage.numRects);
+ std::copy_n(damage.rects, damage.numRects, mSurfaceDamage.begin());
+ return Error::None;
+}
+
+// Layer state functions
+
+Error HWC2On1Adapter::Layer::setBlendMode(BlendMode mode) {
+ mBlendMode = mode;
+ mDisplay.markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setColor(hwc_color_t color) {
+ mColor = color;
+ mDisplay.markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setCompositionType(Composition type) {
+ mCompositionType = type;
+ mDisplay.markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setDataspace(android_dataspace_t) {
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setDisplayFrame(hwc_rect_t frame) {
+ mDisplayFrame = frame;
+ mDisplay.markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setPlaneAlpha(float alpha) {
+ mPlaneAlpha = alpha;
+ mDisplay.markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setSidebandStream(const native_handle_t* stream) {
+ mSidebandStream = stream;
+ mDisplay.markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setSourceCrop(hwc_frect_t crop) {
+ mSourceCrop = crop;
+ mDisplay.markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setTransform(Transform transform) {
+ mTransform = transform;
+ mDisplay.markGeometryChanged();
+ return Error::None;
+}
+
+static bool compareRects(const hwc_rect_t& rect1, const hwc_rect_t& rect2) {
+ return rect1.left == rect2.left &&
+ rect1.right == rect2.right &&
+ rect1.top == rect2.top &&
+ rect1.bottom == rect2.bottom;
+}
+
+Error HWC2On1Adapter::Layer::setVisibleRegion(hwc_region_t visible) {
+ if ((getNumVisibleRegions() != visible.numRects) ||
+ !std::equal(mVisibleRegion.begin(), mVisibleRegion.end(), visible.rects,
+ compareRects)) {
+ mVisibleRegion.resize(visible.numRects);
+ std::copy_n(visible.rects, visible.numRects, mVisibleRegion.begin());
+ mDisplay.markGeometryChanged();
+ }
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setZ(uint32_t z) {
+ mZ = z;
+ return Error::None;
+}
+
+void HWC2On1Adapter::Layer::addReleaseFence(int fenceFd) {
+ ALOGV("addReleaseFence %d to layer %" PRIu64, fenceFd, mId);
+ mReleaseFence.add(fenceFd);
+}
+
+const sp<MiniFence>& HWC2On1Adapter::Layer::getReleaseFence() const {
+ return mReleaseFence.get();
+}
+
+void HWC2On1Adapter::Layer::applyState(hwc_layer_1_t& hwc1Layer) {
+ applyCommonState(hwc1Layer);
+ applyCompositionType(hwc1Layer);
+ switch (mCompositionType) {
+ case Composition::SolidColor : applySolidColorState(hwc1Layer); break;
+ case Composition::Sideband : applySidebandState(hwc1Layer); break;
+ default: applyBufferState(hwc1Layer); break;
+ }
+}
+
+static std::string regionStrings(const std::vector<hwc_rect_t>& visibleRegion,
+ const std::vector<hwc_rect_t>& surfaceDamage) {
+ std::string regions;
+ regions += " Visible Region";
+ regions.resize(40, ' ');
+ regions += "Surface Damage\n";
+
+ size_t numPrinted = 0;
+ size_t maxSize = std::max(visibleRegion.size(), surfaceDamage.size());
+ while (numPrinted < maxSize) {
+ std::string line(" ");
+ if (visibleRegion.empty() && numPrinted == 0) {
+ line += "None";
+ } else if (numPrinted < visibleRegion.size()) {
+ line += rectString(visibleRegion[numPrinted]);
+ }
+ line.resize(40, ' ');
+ if (surfaceDamage.empty() && numPrinted == 0) {
+ line += "None";
+ } else if (numPrinted < surfaceDamage.size()) {
+ line += rectString(surfaceDamage[numPrinted]);
+ }
+ line += '\n';
+ regions += line;
+ ++numPrinted;
+ }
+ return regions;
+}
+
+std::string HWC2On1Adapter::Layer::dump() const {
+ std::stringstream output;
+ const char* fill = " ";
+
+ output << fill << to_string(mCompositionType);
+ output << " Layer HWC2/1: " << mId << "/" << mHwc1Id << " ";
+ output << "Z: " << mZ;
+ if (mCompositionType == HWC2::Composition::SolidColor) {
+ output << " " << colorString(mColor);
+ } else if (mCompositionType == HWC2::Composition::Sideband) {
+ output << " Handle: " << mSidebandStream << '\n';
+ } else {
+ output << " Buffer: " << mBuffer.getBuffer() << "/" <<
+ mBuffer.getFence() << '\n';
+ output << fill << " Display frame [LTRB]: " <<
+ rectString(mDisplayFrame) << '\n';
+ output << fill << " Source crop: " <<
+ frectString(mSourceCrop) << '\n';
+ output << fill << " Transform: " << to_string(mTransform);
+ output << " Blend mode: " << to_string(mBlendMode);
+ if (mPlaneAlpha != 1.0f) {
+ output << " Alpha: " <<
+ alphaString(mPlaneAlpha) << '\n';
+ } else {
+ output << '\n';
+ }
+ output << regionStrings(mVisibleRegion, mSurfaceDamage);
+ }
+ return output.str();
+}
+
+static int getHwc1Blending(HWC2::BlendMode blendMode) {
+ switch (blendMode) {
+ case BlendMode::Coverage: return HWC_BLENDING_COVERAGE;
+ case BlendMode::Premultiplied: return HWC_BLENDING_PREMULT;
+ default: return HWC_BLENDING_NONE;
+ }
+}
+
+void HWC2On1Adapter::Layer::applyCommonState(hwc_layer_1_t& hwc1Layer) {
+ auto minorVersion = mDisplay.getDevice().getHwc1MinorVersion();
+ hwc1Layer.blending = getHwc1Blending(mBlendMode);
+ hwc1Layer.displayFrame = mDisplayFrame;
+
+ auto pendingAlpha = mPlaneAlpha;
+ if (minorVersion < 2) {
+ mHasUnsupportedPlaneAlpha = pendingAlpha < 1.0f;
+ } else {
+ hwc1Layer.planeAlpha =
+ static_cast<uint8_t>(255.0f * pendingAlpha + 0.5f);
+ }
+
+ if (minorVersion < 3) {
+ auto pending = mSourceCrop;
+ hwc1Layer.sourceCropi.left =
+ static_cast<int32_t>(std::ceil(pending.left));
+ hwc1Layer.sourceCropi.top =
+ static_cast<int32_t>(std::ceil(pending.top));
+ hwc1Layer.sourceCropi.right =
+ static_cast<int32_t>(std::floor(pending.right));
+ hwc1Layer.sourceCropi.bottom =
+ static_cast<int32_t>(std::floor(pending.bottom));
+ } else {
+ hwc1Layer.sourceCropf = mSourceCrop;
+ }
+
+ hwc1Layer.transform = static_cast<uint32_t>(mTransform);
+
+ auto& hwc1VisibleRegion = hwc1Layer.visibleRegionScreen;
+ hwc1VisibleRegion.numRects = mVisibleRegion.size();
+ hwc_rect_t* rects = mDisplay.GetRects(hwc1VisibleRegion.numRects);
+ hwc1VisibleRegion.rects = rects;
+ for (size_t i = 0; i < mVisibleRegion.size(); i++) {
+ rects[i] = mVisibleRegion[i];
+ }
+}
+
+void HWC2On1Adapter::Layer::applySolidColorState(hwc_layer_1_t& hwc1Layer) {
+ // If the device does not support background color it is likely to make
+ // assumption regarding backgroundColor and handle (both fields occupy
+ // the same location in hwc_layer_1_t union).
+ // To not confuse these devices we don't set background color and we
+ // make sure handle is a null pointer.
+ if (hasUnsupportedBackgroundColor()) {
+ hwc1Layer.handle = nullptr;
+ } else {
+ hwc1Layer.backgroundColor = mColor;
+ }
+}
+
+void HWC2On1Adapter::Layer::applySidebandState(hwc_layer_1_t& hwc1Layer) {
+ hwc1Layer.sidebandStream = mSidebandStream;
+}
+
+void HWC2On1Adapter::Layer::applyBufferState(hwc_layer_1_t& hwc1Layer) {
+ hwc1Layer.handle = mBuffer.getBuffer();
+ hwc1Layer.acquireFenceFd = mBuffer.getFence();
+}
+
+void HWC2On1Adapter::Layer::applyCompositionType(hwc_layer_1_t& hwc1Layer) {
+ // HWC1 never supports color transforms or dataspaces and only sometimes
+ // supports plane alpha (depending on the version). These require us to drop
+ // some or all layers to client composition.
+ if (mHasUnsupportedPlaneAlpha || mDisplay.hasColorTransform() ||
+ hasUnsupportedBackgroundColor()) {
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ hwc1Layer.flags = HWC_SKIP_LAYER;
+ return;
+ }
+
+ hwc1Layer.flags = 0;
+ switch (mCompositionType) {
+ case Composition::Client:
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ hwc1Layer.flags |= HWC_SKIP_LAYER;
+ break;
+ case Composition::Device:
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ break;
+ case Composition::SolidColor:
+ // In theory the following line should work, but since the HWC1
+ // version of SurfaceFlinger never used HWC_BACKGROUND, HWC1
+ // devices may not work correctly. To be on the safe side, we
+ // fall back to client composition.
+ //
+ // hwc1Layer.compositionType = HWC_BACKGROUND;
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ hwc1Layer.flags |= HWC_SKIP_LAYER;
+ break;
+ case Composition::Cursor:
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ if (mDisplay.getDevice().getHwc1MinorVersion() >= 4) {
+ hwc1Layer.hints |= HWC_IS_CURSOR_LAYER;
+ }
+ break;
+ case Composition::Sideband:
+ if (mDisplay.getDevice().getHwc1MinorVersion() < 4) {
+ hwc1Layer.compositionType = HWC_SIDEBAND;
+ } else {
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ hwc1Layer.flags |= HWC_SKIP_LAYER;
+ }
+ break;
+ default:
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ hwc1Layer.flags |= HWC_SKIP_LAYER;
+ break;
+ }
+ ALOGV("Layer %" PRIu64 " %s set to %d", mId,
+ to_string(mCompositionType).c_str(),
+ hwc1Layer.compositionType);
+ ALOGV_IF(hwc1Layer.flags & HWC_SKIP_LAYER, " and skipping");
+}
+
+// Adapter helpers
+
+void HWC2On1Adapter::populateCapabilities() {
+ if (mHwc1MinorVersion >= 3U) {
+ int supportedTypes = 0;
+ auto result = mHwc1Device->query(mHwc1Device,
+ HWC_DISPLAY_TYPES_SUPPORTED, &supportedTypes);
+ if ((result == 0) && ((supportedTypes & HWC_DISPLAY_VIRTUAL_BIT) != 0)) {
+ ALOGI("Found support for HWC virtual displays");
+ mHwc1SupportsVirtualDisplays = true;
+ }
+ }
+ if (mHwc1MinorVersion >= 4U) {
+ mCapabilities.insert(Capability::SidebandStream);
+ }
+
+ // Check for HWC background color layer support.
+ if (mHwc1MinorVersion >= 1U) {
+ int backgroundColorSupported = 0;
+ auto result = mHwc1Device->query(mHwc1Device,
+ HWC_BACKGROUND_LAYER_SUPPORTED,
+ &backgroundColorSupported);
+ if ((result == 0) && (backgroundColorSupported == 1)) {
+ ALOGV("Found support for HWC background color");
+ mHwc1SupportsBackgroundColor = true;
+ }
+ }
+
+ // Some devices might have HWC1 retire fences that accurately emulate
+ // HWC2 present fences when they are deferred, but it's not very reliable.
+ // To be safe, we indicate PresentFenceIsNotReliable for all HWC1 devices.
+ mCapabilities.insert(Capability::PresentFenceIsNotReliable);
+}
+
+HWC2On1Adapter::Display* HWC2On1Adapter::getDisplay(hwc2_display_t id) {
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ auto display = mDisplays.find(id);
+ if (display == mDisplays.end()) {
+ return nullptr;
+ }
+
+ return display->second.get();
+}
+
+std::tuple<HWC2On1Adapter::Layer*, Error> HWC2On1Adapter::getLayer(
+ hwc2_display_t displayId, hwc2_layer_t layerId) {
+ auto display = getDisplay(displayId);
+ if (!display) {
+ return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadDisplay);
+ }
+
+ auto layerEntry = mLayers.find(layerId);
+ if (layerEntry == mLayers.end()) {
+ return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadLayer);
+ }
+
+ auto layer = layerEntry->second;
+ if (layer->getDisplay().getId() != displayId) {
+ return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadLayer);
+ }
+ return std::make_tuple(layer.get(), Error::None);
+}
+
+void HWC2On1Adapter::populatePrimary() {
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ auto display = std::make_shared<Display>(*this, HWC2::DisplayType::Physical);
+ mHwc1DisplayMap[HWC_DISPLAY_PRIMARY] = display->getId();
+ display->setHwc1Id(HWC_DISPLAY_PRIMARY);
+ display->populateConfigs();
+ mDisplays.emplace(display->getId(), std::move(display));
+}
+
+bool HWC2On1Adapter::prepareAllDisplays() {
+ ATRACE_CALL();
+
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ for (const auto& displayPair : mDisplays) {
+ auto& display = displayPair.second;
+ if (!display->prepare()) {
+ return false;
+ }
+ }
+
+ if (mHwc1DisplayMap.count(HWC_DISPLAY_PRIMARY) == 0) {
+ ALOGE("prepareAllDisplays: Unable to find primary HWC1 display");
+ return false;
+ }
+
+ // Build an array of hwc_display_contents_1 to call prepare() on HWC1.
+ mHwc1Contents.clear();
+
+ // Always push the primary display
+ auto primaryDisplayId = mHwc1DisplayMap[HWC_DISPLAY_PRIMARY];
+ auto& primaryDisplay = mDisplays[primaryDisplayId];
+ mHwc1Contents.push_back(primaryDisplay->getDisplayContents());
+
+ // Push the external display, if present
+ if (mHwc1DisplayMap.count(HWC_DISPLAY_EXTERNAL) != 0) {
+ auto externalDisplayId = mHwc1DisplayMap[HWC_DISPLAY_EXTERNAL];
+ auto& externalDisplay = mDisplays[externalDisplayId];
+ mHwc1Contents.push_back(externalDisplay->getDisplayContents());
+ } else {
+ // Even if an external display isn't present, we still need to send
+ // at least two displays down to HWC1
+ mHwc1Contents.push_back(nullptr);
+ }
+
+ // Push the hardware virtual display, if supported and present
+ if (mHwc1MinorVersion >= 3) {
+ if (mHwc1DisplayMap.count(HWC_DISPLAY_VIRTUAL) != 0) {
+ auto virtualDisplayId = mHwc1DisplayMap[HWC_DISPLAY_VIRTUAL];
+ auto& virtualDisplay = mDisplays[virtualDisplayId];
+ mHwc1Contents.push_back(virtualDisplay->getDisplayContents());
+ } else {
+ mHwc1Contents.push_back(nullptr);
+ }
+ }
+
+ for (auto& displayContents : mHwc1Contents) {
+ if (!displayContents) {
+ continue;
+ }
+
+ ALOGV("Display %zd layers:", mHwc1Contents.size() - 1);
+ for (size_t l = 0; l < displayContents->numHwLayers; ++l) {
+ auto& layer = displayContents->hwLayers[l];
+ ALOGV(" %zd: %d", l, layer.compositionType);
+ }
+ }
+
+ ALOGV("Calling HWC1 prepare");
+ {
+ ATRACE_NAME("HWC1 prepare");
+ mHwc1Device->prepare(mHwc1Device, mHwc1Contents.size(),
+ mHwc1Contents.data());
+ }
+
+ for (size_t c = 0; c < mHwc1Contents.size(); ++c) {
+ auto& contents = mHwc1Contents[c];
+ if (!contents) {
+ continue;
+ }
+ ALOGV("Display %zd layers:", c);
+ for (size_t l = 0; l < contents->numHwLayers; ++l) {
+ ALOGV(" %zd: %d", l, contents->hwLayers[l].compositionType);
+ }
+ }
+
+ // Return the received contents to their respective displays
+ for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
+ if (mHwc1Contents[hwc1Id] == nullptr) {
+ continue;
+ }
+
+ auto displayId = mHwc1DisplayMap[hwc1Id];
+ auto& display = mDisplays[displayId];
+ display->generateChanges();
+ }
+
+ return true;
+}
+
+void dumpHWC1Message(hwc_composer_device_1* device, size_t numDisplays,
+ hwc_display_contents_1_t** displays) {
+ ALOGV("*****************************");
+ size_t displayId = 0;
+ while (displayId < numDisplays) {
+ hwc_display_contents_1_t* display = displays[displayId];
+
+ ALOGV("hwc_display_contents_1_t[%zu] @0x%p", displayId, display);
+ if (display == nullptr) {
+ displayId++;
+ continue;
+ }
+ ALOGV(" retirefd:0x%08x", display->retireFenceFd);
+ ALOGV(" outbuf :0x%p", display->outbuf);
+ ALOGV(" outbuffd:0x%08x", display->outbufAcquireFenceFd);
+ ALOGV(" flags :0x%08x", display->flags);
+ for(size_t layerId=0 ; layerId < display->numHwLayers ; layerId++) {
+ hwc_layer_1_t& layer = display->hwLayers[layerId];
+ ALOGV(" Layer[%zu]:", layerId);
+ ALOGV(" composition : 0x%08x", layer.compositionType);
+ ALOGV(" hints : 0x%08x", layer.hints);
+ ALOGV(" flags : 0x%08x", layer.flags);
+ ALOGV(" handle : 0x%p", layer.handle);
+ ALOGV(" transform : 0x%08x", layer.transform);
+ ALOGV(" blending : 0x%08x", layer.blending);
+ ALOGV(" sourceCropf : %f, %f, %f, %f",
+ layer.sourceCropf.left,
+ layer.sourceCropf.top,
+ layer.sourceCropf.right,
+ layer.sourceCropf.bottom);
+ ALOGV(" displayFrame : %d, %d, %d, %d",
+ layer.displayFrame.left,
+ layer.displayFrame.left,
+ layer.displayFrame.left,
+ layer.displayFrame.left);
+ hwc_region_t& visReg = layer.visibleRegionScreen;
+ ALOGV(" visibleRegionScreen: #0x%08zx[@0x%p]",
+ visReg.numRects,
+ visReg.rects);
+ for (size_t visRegId=0; visRegId < visReg.numRects ; visRegId++) {
+ if (layer.visibleRegionScreen.rects == nullptr) {
+ ALOGV(" null");
+ } else {
+ ALOGV(" visibleRegionScreen[%zu] %d, %d, %d, %d",
+ visRegId,
+ visReg.rects[visRegId].left,
+ visReg.rects[visRegId].top,
+ visReg.rects[visRegId].right,
+ visReg.rects[visRegId].bottom);
+ }
+ }
+ ALOGV(" acquireFenceFd : 0x%08x", layer.acquireFenceFd);
+ ALOGV(" releaseFenceFd : 0x%08x", layer.releaseFenceFd);
+ ALOGV(" planeAlpha : 0x%08x", layer.planeAlpha);
+ if (getMinorVersion(device) < 5)
+ continue;
+ ALOGV(" surfaceDamage : #0x%08zx[@0x%p]",
+ layer.surfaceDamage.numRects,
+ layer.surfaceDamage.rects);
+ for (size_t sdId=0; sdId < layer.surfaceDamage.numRects ; sdId++) {
+ if (layer.surfaceDamage.rects == nullptr) {
+ ALOGV(" null");
+ } else {
+ ALOGV(" surfaceDamage[%zu] %d, %d, %d, %d",
+ sdId,
+ layer.surfaceDamage.rects[sdId].left,
+ layer.surfaceDamage.rects[sdId].top,
+ layer.surfaceDamage.rects[sdId].right,
+ layer.surfaceDamage.rects[sdId].bottom);
+ }
+ }
+ }
+ displayId++;
+ }
+ ALOGV("-----------------------------");
+}
+
+Error HWC2On1Adapter::setAllDisplays() {
+ ATRACE_CALL();
+
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ // Make sure we're ready to validate
+ for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
+ if (mHwc1Contents[hwc1Id] == nullptr) {
+ continue;
+ }
+
+ auto displayId = mHwc1DisplayMap[hwc1Id];
+ auto& display = mDisplays[displayId];
+ Error error = display->set(*mHwc1Contents[hwc1Id]);
+ if (error != Error::None) {
+ ALOGE("setAllDisplays: Failed to set display %zd: %s", hwc1Id,
+ to_string(error).c_str());
+ return error;
+ }
+ }
+
+ ALOGV("Calling HWC1 set");
+ {
+ ATRACE_NAME("HWC1 set");
+ //dumpHWC1Message(mHwc1Device, mHwc1Contents.size(), mHwc1Contents.data());
+ mHwc1Device->set(mHwc1Device, mHwc1Contents.size(),
+ mHwc1Contents.data());
+ }
+
+ // Add retire and release fences
+ for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
+ if (mHwc1Contents[hwc1Id] == nullptr) {
+ continue;
+ }
+
+ auto displayId = mHwc1DisplayMap[hwc1Id];
+ auto& display = mDisplays[displayId];
+ auto retireFenceFd = mHwc1Contents[hwc1Id]->retireFenceFd;
+ ALOGV("setAllDisplays: Adding retire fence %d to display %zd",
+ retireFenceFd, hwc1Id);
+ display->addRetireFence(mHwc1Contents[hwc1Id]->retireFenceFd);
+ display->addReleaseFences(*mHwc1Contents[hwc1Id]);
+ }
+
+ return Error::None;
+}
+
+void HWC2On1Adapter::hwc1Invalidate() {
+ ALOGV("Received hwc1Invalidate");
+
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ // If the HWC2-side callback hasn't been registered yet, buffer this until
+ // it is registered.
+ if (mCallbacks.count(Callback::Refresh) == 0) {
+ mHasPendingInvalidate = true;
+ return;
+ }
+
+ const auto& callbackInfo = mCallbacks[Callback::Refresh];
+ std::vector<hwc2_display_t> displays;
+ for (const auto& displayPair : mDisplays) {
+ displays.emplace_back(displayPair.first);
+ }
+
+ // Call back without the state lock held.
+ lock.unlock();
+
+ auto refresh = reinterpret_cast<HWC2_PFN_REFRESH>(callbackInfo.pointer);
+ for (auto display : displays) {
+ refresh(callbackInfo.data, display);
+ }
+}
+
+void HWC2On1Adapter::hwc1Vsync(int hwc1DisplayId, int64_t timestamp) {
+ ALOGV("Received hwc1Vsync(%d, %" PRId64 ")", hwc1DisplayId, timestamp);
+
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ // If the HWC2-side callback hasn't been registered yet, buffer this until
+ // it is registered.
+ if (mCallbacks.count(Callback::Vsync) == 0) {
+ mPendingVsyncs.emplace_back(hwc1DisplayId, timestamp);
+ return;
+ }
+
+ if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
+ ALOGE("hwc1Vsync: Couldn't find display for HWC1 id %d", hwc1DisplayId);
+ return;
+ }
+
+ const auto& callbackInfo = mCallbacks[Callback::Vsync];
+ auto displayId = mHwc1DisplayMap[hwc1DisplayId];
+
+ // Call back without the state lock held.
+ lock.unlock();
+
+ auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(callbackInfo.pointer);
+ vsync(callbackInfo.data, displayId, timestamp);
+}
+
+void HWC2On1Adapter::hwc1Hotplug(int hwc1DisplayId, int connected) {
+ ALOGV("Received hwc1Hotplug(%d, %d)", hwc1DisplayId, connected);
+
+ if (hwc1DisplayId != HWC_DISPLAY_EXTERNAL) {
+ ALOGE("hwc1Hotplug: Received hotplug for non-external display");
+ return;
+ }
+
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ // If the HWC2-side callback hasn't been registered yet, buffer this until
+ // it is registered
+ if (mCallbacks.count(Callback::Hotplug) == 0) {
+ mPendingHotplugs.emplace_back(hwc1DisplayId, connected);
+ return;
+ }
+
+ hwc2_display_t displayId = UINT64_MAX;
+ if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
+ if (connected == 0) {
+ ALOGW("hwc1Hotplug: Received disconnect for unconnected display");
+ return;
+ }
+
+ // Create a new display on connect
+ auto display = std::make_shared<HWC2On1Adapter::Display>(*this,
+ HWC2::DisplayType::Physical);
+ display->setHwc1Id(HWC_DISPLAY_EXTERNAL);
+ display->populateConfigs();
+ displayId = display->getId();
+ mHwc1DisplayMap[HWC_DISPLAY_EXTERNAL] = displayId;
+ mDisplays.emplace(displayId, std::move(display));
+ } else {
+ if (connected != 0) {
+ ALOGW("hwc1Hotplug: Received connect for previously connected "
+ "display");
+ return;
+ }
+
+ // Disconnect an existing display
+ displayId = mHwc1DisplayMap[hwc1DisplayId];
+ mHwc1DisplayMap.erase(HWC_DISPLAY_EXTERNAL);
+ mDisplays.erase(displayId);
+ }
+
+ const auto& callbackInfo = mCallbacks[Callback::Hotplug];
+
+ // Call back without the state lock held
+ lock.unlock();
+
+ auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(callbackInfo.pointer);
+ auto hwc2Connected = (connected == 0) ?
+ HWC2::Connection::Disconnected : HWC2::Connection::Connected;
+ hotplug(callbackInfo.data, displayId, static_cast<int32_t>(hwc2Connected));
+}
+} // namespace android
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/MiniFence.cpp b/graphics/composer/2.1/utils/hwc2on1adapter/MiniFence.cpp
new file mode 100644
index 0000000..dfbe4d6
--- /dev/null
+++ b/graphics/composer/2.1/utils/hwc2on1adapter/MiniFence.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include "hwc2on1adapter/MiniFence.h"
+
+#include <unistd.h>
+
+namespace android {
+
+const sp<MiniFence> MiniFence::NO_FENCE = sp<MiniFence>(new MiniFence);
+
+MiniFence::MiniFence() :
+ mFenceFd(-1) {
+}
+
+MiniFence::MiniFence(int fenceFd) :
+ mFenceFd(fenceFd) {
+}
+
+MiniFence::~MiniFence() {
+ if (mFenceFd != -1) {
+ close(mFenceFd);
+ }
+}
+
+int MiniFence::dup() const {
+ return ::dup(mFenceFd);
+}
+}
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h b/graphics/composer/2.1/utils/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h
new file mode 100644
index 0000000..3badfce
--- /dev/null
+++ b/graphics/composer/2.1/utils/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h
@@ -0,0 +1,738 @@
+/*
+ * Copyright 2015 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.
+ */
+
+#ifndef ANDROID_SF_HWC2_ON_1_ADAPTER_H
+#define ANDROID_SF_HWC2_ON_1_ADAPTER_H
+
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
+#include "MiniFence.h"
+
+#include <atomic>
+#include <map>
+#include <mutex>
+#include <queue>
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+struct hwc_composer_device_1;
+struct hwc_display_contents_1;
+struct hwc_layer_1;
+
+namespace android {
+
+// For devices unable to provide an implementation of HWC2 (see hwcomposer2.h),
+// we provide an adapter able to talk to HWC1 (see hwcomposer.h). It translates
+// streamed function calls ala HWC2 model to batched array of structs calls ala
+// HWC1 model.
+class HWC2On1Adapter : public hwc2_device_t
+{
+public:
+ explicit HWC2On1Adapter(struct hwc_composer_device_1* hwc1Device);
+ ~HWC2On1Adapter();
+
+ struct hwc_composer_device_1* getHwc1Device() const { return mHwc1Device; }
+ uint8_t getHwc1MinorVersion() const { return mHwc1MinorVersion; }
+
+private:
+ static inline HWC2On1Adapter* getAdapter(hwc2_device_t* device) {
+ return static_cast<HWC2On1Adapter*>(device);
+ }
+
+ // getCapabilities
+
+ void doGetCapabilities(uint32_t* outCount,
+ int32_t* /*hwc2_capability_t*/ outCapabilities);
+ static void getCapabilitiesHook(hwc2_device_t* device, uint32_t* outCount,
+ int32_t* /*hwc2_capability_t*/ outCapabilities) {
+ getAdapter(device)->doGetCapabilities(outCount, outCapabilities);
+ }
+
+ bool supportsBackgroundColor() {
+ return mHwc1SupportsBackgroundColor;
+ }
+
+ // getFunction
+
+ hwc2_function_pointer_t doGetFunction(HWC2::FunctionDescriptor descriptor);
+ static hwc2_function_pointer_t getFunctionHook(hwc2_device_t* device,
+ int32_t intDesc) {
+ auto descriptor = static_cast<HWC2::FunctionDescriptor>(intDesc);
+ return getAdapter(device)->doGetFunction(descriptor);
+ }
+
+ // Device functions
+
+ HWC2::Error createVirtualDisplay(uint32_t width, uint32_t height,
+ hwc2_display_t* outDisplay);
+ static int32_t createVirtualDisplayHook(hwc2_device_t* device,
+ uint32_t width, uint32_t height, int32_t* /*format*/,
+ hwc2_display_t* outDisplay) {
+ // HWC1 implementations cannot override the buffer format requested by
+ // the consumer
+ auto error = getAdapter(device)->createVirtualDisplay(width, height,
+ outDisplay);
+ return static_cast<int32_t>(error);
+ }
+
+ HWC2::Error destroyVirtualDisplay(hwc2_display_t display);
+ static int32_t destroyVirtualDisplayHook(hwc2_device_t* device,
+ hwc2_display_t display) {
+ auto error = getAdapter(device)->destroyVirtualDisplay(display);
+ return static_cast<int32_t>(error);
+ }
+
+ std::string mDumpString;
+ void dump(uint32_t* outSize, char* outBuffer);
+ static void dumpHook(hwc2_device_t* device, uint32_t* outSize,
+ char* outBuffer) {
+ getAdapter(device)->dump(outSize, outBuffer);
+ }
+
+ uint32_t getMaxVirtualDisplayCount();
+ static uint32_t getMaxVirtualDisplayCountHook(hwc2_device_t* device) {
+ return getAdapter(device)->getMaxVirtualDisplayCount();
+ }
+
+ HWC2::Error registerCallback(HWC2::Callback descriptor,
+ hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer);
+ static int32_t registerCallbackHook(hwc2_device_t* device,
+ int32_t intDesc, hwc2_callback_data_t callbackData,
+ hwc2_function_pointer_t pointer) {
+ auto descriptor = static_cast<HWC2::Callback>(intDesc);
+ auto error = getAdapter(device)->registerCallback(descriptor,
+ callbackData, pointer);
+ return static_cast<int32_t>(error);
+ }
+
+ // Display functions
+
+ class Layer;
+
+ class SortLayersByZ {
+ public:
+ bool operator()(const std::shared_ptr<Layer>& lhs,
+ const std::shared_ptr<Layer>& rhs);
+ };
+
+ // The semantics of the fences returned by the device differ between
+ // hwc1.set() and hwc2.present(). Read hwcomposer.h and hwcomposer2.h
+ // for more information.
+ //
+ // Release fences in hwc1 are obtained on set() for a frame n and signaled
+ // when the layer buffer is not needed for read operations anymore
+ // (typically on frame n+1). In HWC2, release fences are obtained with a
+ // special call after present() for frame n. These fences signal
+ // on frame n: More specifically, the fence for a given buffer provided in
+ // frame n will signal when the prior buffer is no longer required.
+ //
+ // A retire fence (HWC1) is signaled when a composition is replaced
+ // on the panel whereas a present fence (HWC2) is signaled when a
+ // composition starts to be displayed on a panel.
+ //
+ // The HWC2to1Adapter emulates the new fence semantics for a frame
+ // n by returning the fence from frame n-1. For frame 0, the adapter
+ // returns NO_FENCE.
+ class DeferredFence {
+ public:
+ DeferredFence()
+ : mFences({MiniFence::NO_FENCE, MiniFence::NO_FENCE}) {}
+
+ void add(int32_t fenceFd) {
+ mFences.emplace(new MiniFence(fenceFd));
+ mFences.pop();
+ }
+
+ const sp<MiniFence>& get() const {
+ return mFences.front();
+ }
+
+ private:
+ // There are always two fences in this queue.
+ std::queue<sp<MiniFence>> mFences;
+ };
+
+ class FencedBuffer {
+ public:
+ FencedBuffer() : mBuffer(nullptr), mFence(MiniFence::NO_FENCE) {}
+
+ void setBuffer(buffer_handle_t buffer) { mBuffer = buffer; }
+ void setFence(int fenceFd) { mFence = new MiniFence(fenceFd); }
+
+ buffer_handle_t getBuffer() const { return mBuffer; }
+ int getFence() const { return mFence->dup(); }
+
+ private:
+ buffer_handle_t mBuffer;
+ sp<MiniFence> mFence;
+ };
+
+ class Display {
+ public:
+ Display(HWC2On1Adapter& device, HWC2::DisplayType type);
+
+ hwc2_display_t getId() const { return mId; }
+ HWC2On1Adapter& getDevice() const { return mDevice; }
+
+ // Does not require locking because it is set before adding the
+ // Displays to the Adapter's list of displays
+ void setHwc1Id(int32_t id) { mHwc1Id = id; }
+ int32_t getHwc1Id() const { return mHwc1Id; }
+
+ // HWC2 Display functions
+ HWC2::Error acceptChanges();
+ HWC2::Error createLayer(hwc2_layer_t* outLayerId);
+ HWC2::Error destroyLayer(hwc2_layer_t layerId);
+ HWC2::Error getActiveConfig(hwc2_config_t* outConfigId);
+ HWC2::Error getAttribute(hwc2_config_t configId,
+ HWC2::Attribute attribute, int32_t* outValue);
+ HWC2::Error getChangedCompositionTypes(uint32_t* outNumElements,
+ hwc2_layer_t* outLayers, int32_t* outTypes);
+ HWC2::Error getColorModes(uint32_t* outNumModes, int32_t* outModes);
+ HWC2::Error getConfigs(uint32_t* outNumConfigs,
+ hwc2_config_t* outConfigIds);
+ HWC2::Error getDozeSupport(int32_t* outSupport);
+ HWC2::Error getHdrCapabilities(uint32_t* outNumTypes,
+ int32_t* outTypes, float* outMaxLuminance,
+ float* outMaxAverageLuminance, float* outMinLuminance);
+ HWC2::Error getName(uint32_t* outSize, char* outName);
+ HWC2::Error getReleaseFences(uint32_t* outNumElements,
+ hwc2_layer_t* outLayers, int32_t* outFences);
+ HWC2::Error getRequests(int32_t* outDisplayRequests,
+ uint32_t* outNumElements, hwc2_layer_t* outLayers,
+ int32_t* outLayerRequests);
+ HWC2::Error getType(int32_t* outType);
+
+ // Since HWC1 "presents" (called "set" in HWC1) all Displays
+ // at once, the first call to any Display::present will trigger
+ // present() on all Displays in the Device. Subsequent calls without
+ // first calling validate() are noop (except for duping/returning
+ // the retire fence).
+ HWC2::Error present(int32_t* outRetireFence);
+
+ HWC2::Error setActiveConfig(hwc2_config_t configId);
+ HWC2::Error setClientTarget(buffer_handle_t target,
+ int32_t acquireFence, int32_t dataspace,
+ hwc_region_t damage);
+ HWC2::Error setColorMode(android_color_mode_t mode);
+ HWC2::Error setColorTransform(android_color_transform_t hint);
+ HWC2::Error setOutputBuffer(buffer_handle_t buffer,
+ int32_t releaseFence);
+ HWC2::Error setPowerMode(HWC2::PowerMode mode);
+ HWC2::Error setVsyncEnabled(HWC2::Vsync enabled);
+
+ // Since HWC1 "validates" (called "prepare" in HWC1) all Displays
+ // at once, the first call to any Display::validate() will trigger
+ // validate() on all other Displays in the Device.
+ HWC2::Error validate(uint32_t* outNumTypes,
+ uint32_t* outNumRequests);
+
+ HWC2::Error updateLayerZ(hwc2_layer_t layerId, uint32_t z);
+
+ HWC2::Error getClientTargetSupport(uint32_t width, uint32_t height,
+ int32_t format, int32_t dataspace);
+
+ // Read configs from HWC1 device
+ void populateConfigs();
+
+ // Set configs for a virtual display
+ void populateConfigs(uint32_t width, uint32_t height);
+
+ bool prepare();
+
+ // Called after hwc.prepare() with responses from the device.
+ void generateChanges();
+
+ bool hasChanges() const;
+ HWC2::Error set(hwc_display_contents_1& hwcContents);
+ void addRetireFence(int fenceFd);
+ void addReleaseFences(const hwc_display_contents_1& hwcContents);
+
+ bool hasColorTransform() const;
+
+ std::string dump() const;
+
+ // Return a rect from the pool allocated during validate()
+ hwc_rect_t* GetRects(size_t numRects);
+
+ hwc_display_contents_1* getDisplayContents();
+
+ void markGeometryChanged() { mGeometryChanged = true; }
+ void resetGeometryMarker() { mGeometryChanged = false;}
+ private:
+ class Config {
+ public:
+ Config(Display& display)
+ : mDisplay(display),
+ mId(0),
+ mAttributes() {}
+
+ bool isOnDisplay(const Display& display) const {
+ return display.getId() == mDisplay.getId();
+ }
+
+ void setAttribute(HWC2::Attribute attribute, int32_t value);
+ int32_t getAttribute(HWC2::Attribute attribute) const;
+
+ void setHwc1Id(uint32_t id);
+ bool hasHwc1Id(uint32_t id) const;
+ HWC2::Error getColorModeForHwc1Id(uint32_t id,
+ android_color_mode_t *outMode) const;
+ HWC2::Error getHwc1IdForColorMode(android_color_mode_t mode,
+ uint32_t* outId) const;
+
+ void setId(hwc2_config_t id) { mId = id; }
+ hwc2_config_t getId() const { return mId; }
+
+ // Attempts to merge two configs that differ only in color
+ // mode. Returns whether the merge was successful
+ bool merge(const Config& other);
+
+ std::set<android_color_mode_t> getColorModes() const;
+
+ // splitLine divides the output into two lines suitable for
+ // dumpsys SurfaceFlinger
+ std::string toString(bool splitLine = false) const;
+
+ private:
+ Display& mDisplay;
+ hwc2_config_t mId;
+ std::unordered_map<HWC2::Attribute, int32_t> mAttributes;
+
+ // Maps from color transform to HWC1 config ID
+ std::unordered_map<android_color_mode_t, uint32_t> mHwc1Ids;
+ };
+
+ // Stores changes requested from the device upon calling prepare().
+ // Handles change request to:
+ // - Layer composition type.
+ // - Layer hints.
+ class Changes {
+ public:
+ uint32_t getNumTypes() const {
+ return static_cast<uint32_t>(mTypeChanges.size());
+ }
+
+ uint32_t getNumLayerRequests() const {
+ return static_cast<uint32_t>(mLayerRequests.size());
+ }
+
+ const std::unordered_map<hwc2_layer_t, HWC2::Composition>&
+ getTypeChanges() const {
+ return mTypeChanges;
+ }
+
+ const std::unordered_map<hwc2_layer_t, HWC2::LayerRequest>&
+ getLayerRequests() const {
+ return mLayerRequests;
+ }
+
+ void addTypeChange(hwc2_layer_t layerId,
+ HWC2::Composition type) {
+ mTypeChanges.insert({layerId, type});
+ }
+
+ void clearTypeChanges() { mTypeChanges.clear(); }
+
+ void addLayerRequest(hwc2_layer_t layerId,
+ HWC2::LayerRequest request) {
+ mLayerRequests.insert({layerId, request});
+ }
+
+ private:
+ std::unordered_map<hwc2_layer_t, HWC2::Composition>
+ mTypeChanges;
+ std::unordered_map<hwc2_layer_t, HWC2::LayerRequest>
+ mLayerRequests;
+ };
+
+ std::shared_ptr<const Config>
+ getConfig(hwc2_config_t configId) const;
+
+ void populateColorModes();
+ void initializeActiveConfig();
+
+ // Creates a bi-directional mapping between index in HWC1
+ // prepare/set array and Layer object. Stores mapping in
+ // mHwc1LayerMap and also updates Layer's attribute mHwc1Id.
+ void assignHwc1LayerIds();
+
+ // Called after a response to prepare() has been received:
+ // Ingest composition type changes requested by the device.
+ void updateTypeChanges(const struct hwc_layer_1& hwc1Layer,
+ const Layer& layer);
+
+ // Called after a response to prepare() has been received:
+ // Ingest layer hint changes requested by the device.
+ void updateLayerRequests(const struct hwc_layer_1& hwc1Layer,
+ const Layer& layer);
+
+ // Set all fields in HWC1 comm array for layer containing the
+ // HWC_FRAMEBUFFER_TARGET (always the last layer).
+ void prepareFramebufferTarget();
+
+ // Display ID generator.
+ static std::atomic<hwc2_display_t> sNextId;
+ const hwc2_display_t mId;
+
+
+ HWC2On1Adapter& mDevice;
+
+ // The state of this display should only be modified from
+ // SurfaceFlinger's main loop, with the exception of when dump is
+ // called. To prevent a bad state from crashing us during a dump
+ // call, all public calls into Display must acquire this mutex.
+ //
+ // It is recursive because we don't want to deadlock in validate
+ // (or present) when we call HWC2On1Adapter::prepareAllDisplays
+ // (or setAllDisplays), which calls back into Display functions
+ // which require locking.
+ mutable std::recursive_mutex mStateMutex;
+
+ // Allocate RAM able to store all layers and rects used for
+ // communication with HWC1. Place allocated RAM in variable
+ // mHwc1RequestedContents.
+ void allocateRequestedContents();
+
+ // Array of structs exchanged between client and hwc1 device.
+ // Sent to device upon calling prepare().
+ std::unique_ptr<hwc_display_contents_1> mHwc1RequestedContents;
+ private:
+ DeferredFence mRetireFence;
+
+ // Will only be non-null after the Display has been validated and
+ // before it has been presented
+ std::unique_ptr<Changes> mChanges;
+
+ int32_t mHwc1Id;
+
+ std::vector<std::shared_ptr<Config>> mConfigs;
+ std::shared_ptr<const Config> mActiveConfig;
+ std::set<android_color_mode_t> mColorModes;
+ android_color_mode_t mActiveColorMode;
+ std::string mName;
+ HWC2::DisplayType mType;
+ HWC2::PowerMode mPowerMode;
+ HWC2::Vsync mVsyncEnabled;
+
+ // Used to populate HWC1 HWC_FRAMEBUFFER_TARGET layer
+ FencedBuffer mClientTarget;
+
+
+ FencedBuffer mOutputBuffer;
+
+ bool mHasColorTransform;
+
+ // All layers this Display is aware of.
+ std::multiset<std::shared_ptr<Layer>, SortLayersByZ> mLayers;
+
+ // Mapping between layer index in array of hwc_display_contents_1*
+ // passed to HWC1 during validate/set and Layer object.
+ std::unordered_map<size_t, std::shared_ptr<Layer>> mHwc1LayerMap;
+
+ // All communication with HWC1 via prepare/set is done with one
+ // alloc. This pointer is pointing to a pool of hwc_rect_t.
+ size_t mNumAvailableRects;
+ hwc_rect_t* mNextAvailableRect;
+
+ // True if any of the Layers contained in this Display have been
+ // updated with anything other than a buffer since last call to
+ // Display::set()
+ bool mGeometryChanged;
+ };
+
+ // Utility template calling a Display object method directly based on the
+ // hwc2_display_t displayId parameter.
+ template <typename ...Args>
+ static int32_t callDisplayFunction(hwc2_device_t* device,
+ hwc2_display_t displayId, HWC2::Error (Display::*member)(Args...),
+ Args... args) {
+ auto display = getAdapter(device)->getDisplay(displayId);
+ if (!display) {
+ return static_cast<int32_t>(HWC2::Error::BadDisplay);
+ }
+ auto error = ((*display).*member)(std::forward<Args>(args)...);
+ return static_cast<int32_t>(error);
+ }
+
+ template <typename MF, MF memFunc, typename ...Args>
+ static int32_t displayHook(hwc2_device_t* device, hwc2_display_t displayId,
+ Args... args) {
+ return HWC2On1Adapter::callDisplayFunction(device, displayId, memFunc,
+ std::forward<Args>(args)...);
+ }
+
+ static int32_t getDisplayAttributeHook(hwc2_device_t* device,
+ hwc2_display_t display, hwc2_config_t config,
+ int32_t intAttribute, int32_t* outValue) {
+ auto attribute = static_cast<HWC2::Attribute>(intAttribute);
+ return callDisplayFunction(device, display, &Display::getAttribute,
+ config, attribute, outValue);
+ }
+
+ static int32_t setColorTransformHook(hwc2_device_t* device,
+ hwc2_display_t display, const float* /*matrix*/,
+ int32_t /*android_color_transform_t*/ intHint) {
+ // We intentionally throw away the matrix, because if the hint is
+ // anything other than IDENTITY, we have to fall back to client
+ // composition anyway
+ auto hint = static_cast<android_color_transform_t>(intHint);
+ return callDisplayFunction(device, display, &Display::setColorTransform,
+ hint);
+ }
+
+ static int32_t setColorModeHook(hwc2_device_t* device,
+ hwc2_display_t display, int32_t /*android_color_mode_t*/ intMode) {
+ auto mode = static_cast<android_color_mode_t>(intMode);
+ return callDisplayFunction(device, display, &Display::setColorMode,
+ mode);
+ }
+
+ static int32_t setPowerModeHook(hwc2_device_t* device,
+ hwc2_display_t display, int32_t intMode) {
+ auto mode = static_cast<HWC2::PowerMode>(intMode);
+ return callDisplayFunction(device, display, &Display::setPowerMode,
+ mode);
+ }
+
+ static int32_t setVsyncEnabledHook(hwc2_device_t* device,
+ hwc2_display_t display, int32_t intEnabled) {
+ auto enabled = static_cast<HWC2::Vsync>(intEnabled);
+ return callDisplayFunction(device, display, &Display::setVsyncEnabled,
+ enabled);
+ }
+
+ class Layer {
+ public:
+ explicit Layer(Display& display);
+
+ bool operator==(const Layer& other) { return mId == other.mId; }
+ bool operator!=(const Layer& other) { return !(*this == other); }
+
+ hwc2_layer_t getId() const { return mId; }
+ Display& getDisplay() const { return mDisplay; }
+
+ // HWC2 Layer functions
+ HWC2::Error setBuffer(buffer_handle_t buffer, int32_t acquireFence);
+ HWC2::Error setCursorPosition(int32_t x, int32_t y);
+ HWC2::Error setSurfaceDamage(hwc_region_t damage);
+
+ // HWC2 Layer state functions
+ HWC2::Error setBlendMode(HWC2::BlendMode mode);
+ HWC2::Error setColor(hwc_color_t color);
+ HWC2::Error setCompositionType(HWC2::Composition type);
+ HWC2::Error setDataspace(android_dataspace_t dataspace);
+ HWC2::Error setDisplayFrame(hwc_rect_t frame);
+ HWC2::Error setPlaneAlpha(float alpha);
+ HWC2::Error setSidebandStream(const native_handle_t* stream);
+ HWC2::Error setSourceCrop(hwc_frect_t crop);
+ HWC2::Error setTransform(HWC2::Transform transform);
+ HWC2::Error setVisibleRegion(hwc_region_t visible);
+ HWC2::Error setZ(uint32_t z);
+
+ HWC2::Composition getCompositionType() const {
+ return mCompositionType;
+ }
+ uint32_t getZ() const { return mZ; }
+
+ void addReleaseFence(int fenceFd);
+ const sp<MiniFence>& getReleaseFence() const;
+
+ void setHwc1Id(size_t id) { mHwc1Id = id; }
+ size_t getHwc1Id() const { return mHwc1Id; }
+
+ // Write state to HWC1 communication struct.
+ void applyState(struct hwc_layer_1& hwc1Layer);
+
+ std::string dump() const;
+
+ std::size_t getNumVisibleRegions() { return mVisibleRegion.size(); }
+
+ std::size_t getNumSurfaceDamages() { return mSurfaceDamage.size(); }
+
+ // True if a layer cannot be properly rendered by the device due
+ // to usage of SolidColor (a.k.a BackgroundColor in HWC1).
+ bool hasUnsupportedBackgroundColor() {
+ return (mCompositionType == HWC2::Composition::SolidColor &&
+ !mDisplay.getDevice().supportsBackgroundColor());
+ }
+ private:
+ void applyCommonState(struct hwc_layer_1& hwc1Layer);
+ void applySolidColorState(struct hwc_layer_1& hwc1Layer);
+ void applySidebandState(struct hwc_layer_1& hwc1Layer);
+ void applyBufferState(struct hwc_layer_1& hwc1Layer);
+ void applyCompositionType(struct hwc_layer_1& hwc1Layer);
+
+ static std::atomic<hwc2_layer_t> sNextId;
+ const hwc2_layer_t mId;
+ Display& mDisplay;
+
+ FencedBuffer mBuffer;
+ std::vector<hwc_rect_t> mSurfaceDamage;
+
+ HWC2::BlendMode mBlendMode;
+ hwc_color_t mColor;
+ HWC2::Composition mCompositionType;
+ hwc_rect_t mDisplayFrame;
+ float mPlaneAlpha;
+ const native_handle_t* mSidebandStream;
+ hwc_frect_t mSourceCrop;
+ HWC2::Transform mTransform;
+ std::vector<hwc_rect_t> mVisibleRegion;
+
+ uint32_t mZ;
+
+ DeferredFence mReleaseFence;
+
+ size_t mHwc1Id;
+ bool mHasUnsupportedPlaneAlpha;
+ };
+
+ // Utility tempate calling a Layer object method based on ID parameters:
+ // hwc2_display_t displayId
+ // and
+ // hwc2_layer_t layerId
+ template <typename ...Args>
+ static int32_t callLayerFunction(hwc2_device_t* device,
+ hwc2_display_t displayId, hwc2_layer_t layerId,
+ HWC2::Error (Layer::*member)(Args...), Args... args) {
+ auto result = getAdapter(device)->getLayer(displayId, layerId);
+ auto error = std::get<HWC2::Error>(result);
+ if (error == HWC2::Error::None) {
+ auto layer = std::get<Layer*>(result);
+ error = ((*layer).*member)(std::forward<Args>(args)...);
+ }
+ return static_cast<int32_t>(error);
+ }
+
+ template <typename MF, MF memFunc, typename ...Args>
+ static int32_t layerHook(hwc2_device_t* device, hwc2_display_t displayId,
+ hwc2_layer_t layerId, Args... args) {
+ return HWC2On1Adapter::callLayerFunction(device, displayId, layerId,
+ memFunc, std::forward<Args>(args)...);
+ }
+
+ // Layer state functions
+
+ static int32_t setLayerBlendModeHook(hwc2_device_t* device,
+ hwc2_display_t display, hwc2_layer_t layer, int32_t intMode) {
+ auto mode = static_cast<HWC2::BlendMode>(intMode);
+ return callLayerFunction(device, display, layer,
+ &Layer::setBlendMode, mode);
+ }
+
+ static int32_t setLayerCompositionTypeHook(hwc2_device_t* device,
+ hwc2_display_t display, hwc2_layer_t layer, int32_t intType) {
+ auto type = static_cast<HWC2::Composition>(intType);
+ return callLayerFunction(device, display, layer,
+ &Layer::setCompositionType, type);
+ }
+
+ static int32_t setLayerDataspaceHook(hwc2_device_t* device,
+ hwc2_display_t display, hwc2_layer_t layer, int32_t intDataspace) {
+ auto dataspace = static_cast<android_dataspace_t>(intDataspace);
+ return callLayerFunction(device, display, layer, &Layer::setDataspace,
+ dataspace);
+ }
+
+ static int32_t setLayerTransformHook(hwc2_device_t* device,
+ hwc2_display_t display, hwc2_layer_t layer, int32_t intTransform) {
+ auto transform = static_cast<HWC2::Transform>(intTransform);
+ return callLayerFunction(device, display, layer, &Layer::setTransform,
+ transform);
+ }
+
+ static int32_t setLayerZOrderHook(hwc2_device_t* device,
+ hwc2_display_t display, hwc2_layer_t layer, uint32_t z) {
+ return callDisplayFunction(device, display, &Display::updateLayerZ,
+ layer, z);
+ }
+
+ // Adapter internals
+
+ void populateCapabilities();
+ Display* getDisplay(hwc2_display_t id);
+ std::tuple<Layer*, HWC2::Error> getLayer(hwc2_display_t displayId,
+ hwc2_layer_t layerId);
+ void populatePrimary();
+
+ bool prepareAllDisplays();
+ std::vector<struct hwc_display_contents_1*> mHwc1Contents;
+ HWC2::Error setAllDisplays();
+
+ // Callbacks
+ void hwc1Invalidate();
+ void hwc1Vsync(int hwc1DisplayId, int64_t timestamp);
+ void hwc1Hotplug(int hwc1DisplayId, int connected);
+
+ // These are set in the constructor and before any asynchronous events are
+ // possible
+
+ struct hwc_composer_device_1* const mHwc1Device;
+ const uint8_t mHwc1MinorVersion;
+ bool mHwc1SupportsVirtualDisplays;
+ bool mHwc1SupportsBackgroundColor;
+
+ class Callbacks;
+ const std::unique_ptr<Callbacks> mHwc1Callbacks;
+
+ std::unordered_set<HWC2::Capability> mCapabilities;
+
+ // These are only accessed from the main SurfaceFlinger thread (not from
+ // callbacks or dump
+
+ std::map<hwc2_layer_t, std::shared_ptr<Layer>> mLayers;
+
+ // A HWC1 supports only one virtual display.
+ std::shared_ptr<Display> mHwc1VirtualDisplay;
+
+ // These are potentially accessed from multiple threads, and are protected
+ // by this mutex. This needs to be recursive, since the HWC1 implementation
+ // can call back into the invalidate callback on the same thread that is
+ // calling prepare.
+ std::recursive_timed_mutex mStateMutex;
+
+ struct CallbackInfo {
+ hwc2_callback_data_t data;
+ hwc2_function_pointer_t pointer;
+ };
+ std::unordered_map<HWC2::Callback, CallbackInfo> mCallbacks;
+ bool mHasPendingInvalidate;
+
+ // There is a small gap between the time the HWC1 module is started and
+ // when the callbacks for vsync and hotplugs are registered by the
+ // HWC2on1Adapter. To prevent losing events they are stored in these arrays
+ // and fed to the callback as soon as possible.
+ std::vector<std::pair<int, int64_t>> mPendingVsyncs;
+ std::vector<std::pair<int, int>> mPendingHotplugs;
+
+ // Mapping between HWC1 display id and Display objects.
+ std::map<hwc2_display_t, std::shared_ptr<Display>> mDisplays;
+
+ // Map HWC1 display type (HWC_DISPLAY_PRIMARY, HWC_DISPLAY_EXTERNAL,
+ // HWC_DISPLAY_VIRTUAL) to Display IDs generated by HWC2on1Adapter objects.
+ std::unordered_map<int, hwc2_display_t> mHwc1DisplayMap;
+};
+
+} // namespace android
+
+#endif
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/include/hwc2on1adapter/MiniFence.h b/graphics/composer/2.1/utils/hwc2on1adapter/include/hwc2on1adapter/MiniFence.h
new file mode 100644
index 0000000..75de764
--- /dev/null
+++ b/graphics/composer/2.1/utils/hwc2on1adapter/include/hwc2on1adapter/MiniFence.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef MINIFENCE_H
+#define MINIFENCE_H
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+/* MiniFence is a minimal re-implementation of Fence from libui. It exists to
+ * avoid linking the HWC2on1Adapter to libui and satisfy Treble requirements.
+ */
+class MiniFence : public LightRefBase<MiniFence> {
+public:
+ static const sp<MiniFence> NO_FENCE;
+
+ // Construct a new MiniFence object with an invalid file descriptor.
+ MiniFence();
+
+ // Construct a new MiniFence object to manage a given fence file descriptor.
+ // When the new MiniFence object is destructed the file descriptor will be
+ // closed.
+ explicit MiniFence(int fenceFd);
+
+ // Not copyable or movable.
+ MiniFence(const MiniFence& rhs) = delete;
+ MiniFence& operator=(const MiniFence& rhs) = delete;
+ MiniFence(MiniFence&& rhs) = delete;
+ MiniFence& operator=(MiniFence&& rhs) = delete;
+
+ // Return a duplicate of the fence file descriptor. The caller is
+ // responsible for closing the returned file descriptor. On error, -1 will
+ // be returned and errno will indicate the problem.
+ int dup() const;
+
+private:
+ // Only allow instantiation using ref counting.
+ friend class LightRefBase<MiniFence>;
+ ~MiniFence();
+
+ int mFenceFd;
+
+};
+}
+#endif //MINIFENCE_H
diff --git a/graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp b/graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp
new file mode 100644
index 0000000..73a41f7
--- /dev/null
+++ b/graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp
@@ -0,0 +1,33 @@
+// Copyright 2010 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.
+
+cc_library_shared {
+ name: "libhwc2onfbadapter",
+ vendor: true,
+
+ clang: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+
+ srcs: [
+ "HWC2OnFbAdapter.cpp",
+ ],
+
+ header_libs: ["libhardware_headers"],
+ shared_libs: ["liblog", "libsync"],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.1/utils/hwc2onfbadapter/HWC2OnFbAdapter.cpp b/graphics/composer/2.1/utils/hwc2onfbadapter/HWC2OnFbAdapter.cpp
new file mode 100644
index 0000000..7c9e651
--- /dev/null
+++ b/graphics/composer/2.1/utils/hwc2onfbadapter/HWC2OnFbAdapter.cpp
@@ -0,0 +1,887 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#define LOG_TAG "HWC2OnFbAdapter"
+
+//#define LOG_NDEBUG 0
+
+#include "hwc2onfbadapter/HWC2OnFbAdapter.h"
+
+#include <algorithm>
+#include <type_traits>
+
+#include <inttypes.h>
+#include <time.h>
+#include <sys/prctl.h>
+#include <unistd.h> // for close
+
+#include <hardware/fb.h>
+#include <log/log.h>
+#include <sync/sync.h>
+
+namespace android {
+
+namespace {
+
+void dumpHook(hwc2_device_t* device, uint32_t* outSize, char* outBuffer) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (outBuffer) {
+ *outSize = adapter.getDebugString().copy(outBuffer, *outSize);
+ } else {
+ adapter.updateDebugString();
+ *outSize = adapter.getDebugString().size();
+ }
+}
+
+int32_t registerCallbackHook(hwc2_device_t* device, int32_t descriptor,
+ hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ switch (descriptor) {
+ case HWC2_CALLBACK_HOTPLUG:
+ if (pointer) {
+ reinterpret_cast<HWC2_PFN_HOTPLUG>(pointer)(callbackData, adapter.getDisplayId(),
+ HWC2_CONNECTION_CONNECTED);
+ }
+ break;
+ case HWC2_CALLBACK_REFRESH:
+ break;
+ case HWC2_CALLBACK_VSYNC:
+ adapter.setVsyncCallback(reinterpret_cast<HWC2_PFN_VSYNC>(pointer), callbackData);
+ break;
+ default:
+ return HWC2_ERROR_BAD_PARAMETER;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+uint32_t getMaxVirtualDisplayCountHook(hwc2_device_t* /*device*/) {
+ return 0;
+}
+
+int32_t createVirtualDisplayHook(hwc2_device_t* /*device*/, uint32_t /*width*/, uint32_t /*height*/,
+ int32_t* /*format*/, hwc2_display_t* /*outDisplay*/) {
+ return HWC2_ERROR_NO_RESOURCES;
+}
+
+int32_t destroyVirtualDisplayHook(hwc2_device_t* /*device*/, hwc2_display_t /*display*/) {
+ return HWC2_ERROR_BAD_DISPLAY;
+}
+
+int32_t setOutputBufferHook(hwc2_device_t* /*device*/, hwc2_display_t /*display*/,
+ buffer_handle_t /*buffer*/, int32_t /*releaseFence*/) {
+ return HWC2_ERROR_BAD_DISPLAY;
+}
+
+int32_t getDisplayNameHook(hwc2_device_t* device, hwc2_display_t display, uint32_t* outSize,
+ char* outName) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ const auto& info = adapter.getInfo();
+ if (outName) {
+ *outSize = info.name.copy(outName, *outSize);
+ } else {
+ *outSize = info.name.size();
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getDisplayTypeHook(hwc2_device_t* device, hwc2_display_t display, int32_t* outType) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outType = HWC2_DISPLAY_TYPE_PHYSICAL;
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getDozeSupportHook(hwc2_device_t* device, hwc2_display_t display, int32_t* outSupport) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outSupport = 0;
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getHdrCapabilitiesHook(hwc2_device_t* device, hwc2_display_t display, uint32_t* outNumTypes,
+ int32_t* /*outTypes*/, float* /*outMaxLuminance*/,
+ float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outNumTypes = 0;
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setPowerModeHook(hwc2_device_t* device, hwc2_display_t display, int32_t /*mode*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ // pretend that it works
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setVsyncEnabledHook(hwc2_device_t* device, hwc2_display_t display, int32_t enabled) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ adapter.enableVsync(enabled == HWC2_VSYNC_ENABLE);
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getColorModesHook(hwc2_device_t* device, hwc2_display_t display, uint32_t* outNumModes,
+ int32_t* outModes) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ if (outModes) {
+ if (*outNumModes > 0) {
+ outModes[0] = HAL_COLOR_MODE_NATIVE;
+ *outNumModes = 1;
+ }
+ } else {
+ *outNumModes = 1;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setColorModeHook(hwc2_device_t* device, hwc2_display_t display, int32_t mode) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (mode != HAL_COLOR_MODE_NATIVE) {
+ return HWC2_ERROR_BAD_PARAMETER;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setColorTransformHook(hwc2_device_t* device, hwc2_display_t display,
+ const float* /*matrix*/, int32_t /*hint*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ // we always force client composition
+ adapter.setState(HWC2OnFbAdapter::State::MODIFIED);
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getClientTargetSupportHook(hwc2_device_t* device, hwc2_display_t display, uint32_t width,
+ uint32_t height, int32_t format, int32_t dataspace) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (dataspace != HAL_DATASPACE_UNKNOWN) {
+ return HWC2_ERROR_UNSUPPORTED;
+ }
+
+ const auto& info = adapter.getInfo();
+ return (info.width == width && info.height == height && info.format == format)
+ ? HWC2_ERROR_NONE
+ : HWC2_ERROR_UNSUPPORTED;
+}
+
+int32_t setClientTargetHook(hwc2_device_t* device, hwc2_display_t display, buffer_handle_t target,
+ int32_t acquireFence, int32_t dataspace, hwc_region_t /*damage*/) {
+ if (acquireFence >= 0) {
+ sync_wait(acquireFence, -1);
+ close(acquireFence);
+ }
+
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (dataspace != HAL_DATASPACE_UNKNOWN) {
+ return HWC2_ERROR_BAD_PARAMETER;
+ }
+
+ // no state change
+ adapter.setBuffer(target);
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getDisplayConfigsHook(hwc2_device_t* device, hwc2_display_t display,
+ uint32_t* outNumConfigs, hwc2_config_t* outConfigs) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ if (outConfigs) {
+ if (*outNumConfigs > 0) {
+ outConfigs[0] = adapter.getConfigId();
+ *outNumConfigs = 1;
+ }
+ } else {
+ *outNumConfigs = 1;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getDisplayAttributeHook(hwc2_device_t* device, hwc2_display_t display, hwc2_config_t config,
+ int32_t attribute, int32_t* outValue) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getConfigId() != config) {
+ return HWC2_ERROR_BAD_CONFIG;
+ }
+
+ const auto& info = adapter.getInfo();
+ switch (attribute) {
+ case HWC2_ATTRIBUTE_WIDTH:
+ *outValue = int32_t(info.width);
+ break;
+ case HWC2_ATTRIBUTE_HEIGHT:
+ *outValue = int32_t(info.height);
+ break;
+ case HWC2_ATTRIBUTE_VSYNC_PERIOD:
+ *outValue = int32_t(info.vsync_period_ns);
+ break;
+ case HWC2_ATTRIBUTE_DPI_X:
+ *outValue = int32_t(info.xdpi_scaled);
+ break;
+ case HWC2_ATTRIBUTE_DPI_Y:
+ *outValue = int32_t(info.ydpi_scaled);
+ break;
+ default:
+ return HWC2_ERROR_BAD_PARAMETER;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getActiveConfigHook(hwc2_device_t* device, hwc2_display_t display,
+ hwc2_config_t* outConfig) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outConfig = adapter.getConfigId();
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setActiveConfigHook(hwc2_device_t* device, hwc2_display_t display, hwc2_config_t config) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getConfigId() != config) {
+ return HWC2_ERROR_BAD_CONFIG;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t validateDisplayHook(hwc2_device_t* device, hwc2_display_t display, uint32_t* outNumTypes,
+ uint32_t* outNumRequests) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ const auto& dirtyLayers = adapter.getDirtyLayers();
+ *outNumTypes = dirtyLayers.size();
+ *outNumRequests = 0;
+
+ if (*outNumTypes > 0) {
+ adapter.setState(HWC2OnFbAdapter::State::VALIDATED_WITH_CHANGES);
+ return HWC2_ERROR_HAS_CHANGES;
+ } else {
+ adapter.setState(HWC2OnFbAdapter::State::VALIDATED);
+ return HWC2_ERROR_NONE;
+ }
+}
+
+int32_t getChangedCompositionTypesHook(hwc2_device_t* device, hwc2_display_t display,
+ uint32_t* outNumElements, hwc2_layer_t* outLayers,
+ int32_t* outTypes) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getState() == HWC2OnFbAdapter::State::MODIFIED) {
+ return HWC2_ERROR_NOT_VALIDATED;
+ }
+
+ // request client composition for all layers
+ const auto& dirtyLayers = adapter.getDirtyLayers();
+ if (outLayers && outTypes) {
+ *outNumElements = std::min(*outNumElements, uint32_t(dirtyLayers.size()));
+ auto iter = dirtyLayers.cbegin();
+ for (uint32_t i = 0; i < *outNumElements; i++) {
+ outLayers[i] = *iter++;
+ outTypes[i] = HWC2_COMPOSITION_CLIENT;
+ }
+ } else {
+ *outNumElements = dirtyLayers.size();
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getDisplayRequestsHook(hwc2_device_t* device, hwc2_display_t display,
+ int32_t* outDisplayRequests, uint32_t* outNumElements,
+ hwc2_layer_t* /*outLayers*/, int32_t* /*outLayerRequests*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getState() == HWC2OnFbAdapter::State::MODIFIED) {
+ return HWC2_ERROR_NOT_VALIDATED;
+ }
+
+ *outDisplayRequests = 0;
+ *outNumElements = 0;
+ return HWC2_ERROR_NONE;
+}
+
+int32_t acceptDisplayChangesHook(hwc2_device_t* device, hwc2_display_t display) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getState() == HWC2OnFbAdapter::State::MODIFIED) {
+ return HWC2_ERROR_NOT_VALIDATED;
+ }
+
+ adapter.clearDirtyLayers();
+ adapter.setState(HWC2OnFbAdapter::State::VALIDATED);
+ return HWC2_ERROR_NONE;
+}
+
+int32_t presentDisplayHook(hwc2_device_t* device, hwc2_display_t display,
+ int32_t* outPresentFence) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getState() != HWC2OnFbAdapter::State::VALIDATED) {
+ return HWC2_ERROR_NOT_VALIDATED;
+ }
+
+ adapter.postBuffer();
+ *outPresentFence = -1;
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getReleaseFencesHook(hwc2_device_t* device, hwc2_display_t display,
+ uint32_t* outNumElements, hwc2_layer_t* /*outLayers*/,
+ int32_t* /*outFences*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outNumElements = 0;
+ return HWC2_ERROR_NONE;
+}
+
+int32_t createLayerHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t* outLayer) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outLayer = adapter.addLayer();
+ adapter.setState(HWC2OnFbAdapter::State::MODIFIED);
+ return HWC2_ERROR_NONE;
+}
+
+int32_t destroyLayerHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ if (adapter.removeLayer(layer)) {
+ adapter.setState(HWC2OnFbAdapter::State::MODIFIED);
+ return HWC2_ERROR_NONE;
+ } else {
+ return HWC2_ERROR_BAD_LAYER;
+ }
+}
+
+int32_t setCursorPositionHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t /*layer*/,
+ int32_t /*x*/, int32_t /*y*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ // always an error
+ return HWC2_ERROR_BAD_LAYER;
+}
+
+int32_t setLayerBufferHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer,
+ buffer_handle_t /*buffer*/, int32_t acquireFence) {
+ if (acquireFence >= 0) {
+ sync_wait(acquireFence, -1);
+ close(acquireFence);
+ }
+
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (!adapter.hasLayer(layer)) {
+ return HWC2_ERROR_BAD_LAYER;
+ }
+
+ // no state change
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setLayerSurfaceDamageHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer,
+ hwc_region_t /*damage*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (!adapter.hasLayer(layer)) {
+ return HWC2_ERROR_BAD_LAYER;
+ }
+
+ // no state change
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setLayerCompositionTypeHook(hwc2_device_t* device, hwc2_display_t display,
+ hwc2_layer_t layer, int32_t type) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (!adapter.markLayerDirty(layer, type != HWC2_COMPOSITION_CLIENT)) {
+ return HWC2_ERROR_BAD_LAYER;
+ }
+
+ adapter.setState(HWC2OnFbAdapter::State::MODIFIED);
+ return HWC2_ERROR_NONE;
+}
+
+template <typename... Args>
+int32_t setLayerStateHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer,
+ Args... /*args*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (!adapter.hasLayer(layer)) {
+ return HWC2_ERROR_BAD_LAYER;
+ }
+
+ adapter.setState(HWC2OnFbAdapter::State::MODIFIED);
+ return HWC2_ERROR_NONE;
+}
+
+template <typename PFN, typename T>
+static hwc2_function_pointer_t asFP(T function) {
+ static_assert(std::is_same<PFN, T>::value, "Incompatible function pointer");
+ return reinterpret_cast<hwc2_function_pointer_t>(function);
+}
+
+hwc2_function_pointer_t getFunctionHook(hwc2_device_t* /*device*/, int32_t descriptor) {
+ switch (descriptor) {
+ // global functions
+ case HWC2_FUNCTION_DUMP:
+ return asFP<HWC2_PFN_DUMP>(dumpHook);
+ case HWC2_FUNCTION_REGISTER_CALLBACK:
+ return asFP<HWC2_PFN_REGISTER_CALLBACK>(registerCallbackHook);
+
+ // virtual display functions
+ case HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT:
+ return asFP<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(getMaxVirtualDisplayCountHook);
+ case HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY:
+ return asFP<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(createVirtualDisplayHook);
+ case HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY:
+ return asFP<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(destroyVirtualDisplayHook);
+ case HWC2_FUNCTION_SET_OUTPUT_BUFFER:
+ return asFP<HWC2_PFN_SET_OUTPUT_BUFFER>(setOutputBufferHook);
+
+ // display functions
+ case HWC2_FUNCTION_GET_DISPLAY_NAME:
+ return asFP<HWC2_PFN_GET_DISPLAY_NAME>(getDisplayNameHook);
+ case HWC2_FUNCTION_GET_DISPLAY_TYPE:
+ return asFP<HWC2_PFN_GET_DISPLAY_TYPE>(getDisplayTypeHook);
+ case HWC2_FUNCTION_GET_DOZE_SUPPORT:
+ return asFP<HWC2_PFN_GET_DOZE_SUPPORT>(getDozeSupportHook);
+ case HWC2_FUNCTION_GET_HDR_CAPABILITIES:
+ return asFP<HWC2_PFN_GET_HDR_CAPABILITIES>(getHdrCapabilitiesHook);
+ case HWC2_FUNCTION_SET_POWER_MODE:
+ return asFP<HWC2_PFN_SET_POWER_MODE>(setPowerModeHook);
+ case HWC2_FUNCTION_SET_VSYNC_ENABLED:
+ return asFP<HWC2_PFN_SET_VSYNC_ENABLED>(setVsyncEnabledHook);
+ case HWC2_FUNCTION_GET_COLOR_MODES:
+ return asFP<HWC2_PFN_GET_COLOR_MODES>(getColorModesHook);
+ case HWC2_FUNCTION_SET_COLOR_MODE:
+ return asFP<HWC2_PFN_SET_COLOR_MODE>(setColorModeHook);
+ case HWC2_FUNCTION_SET_COLOR_TRANSFORM:
+ return asFP<HWC2_PFN_SET_COLOR_TRANSFORM>(setColorTransformHook);
+ case HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT:
+ return asFP<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(getClientTargetSupportHook);
+ case HWC2_FUNCTION_SET_CLIENT_TARGET:
+ return asFP<HWC2_PFN_SET_CLIENT_TARGET>(setClientTargetHook);
+
+ // config functions
+ case HWC2_FUNCTION_GET_DISPLAY_CONFIGS:
+ return asFP<HWC2_PFN_GET_DISPLAY_CONFIGS>(getDisplayConfigsHook);
+ case HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE:
+ return asFP<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(getDisplayAttributeHook);
+ case HWC2_FUNCTION_GET_ACTIVE_CONFIG:
+ return asFP<HWC2_PFN_GET_ACTIVE_CONFIG>(getActiveConfigHook);
+ case HWC2_FUNCTION_SET_ACTIVE_CONFIG:
+ return asFP<HWC2_PFN_SET_ACTIVE_CONFIG>(setActiveConfigHook);
+
+ // validate/present functions
+ case HWC2_FUNCTION_VALIDATE_DISPLAY:
+ return asFP<HWC2_PFN_VALIDATE_DISPLAY>(validateDisplayHook);
+ case HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES:
+ return asFP<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(getChangedCompositionTypesHook);
+ case HWC2_FUNCTION_GET_DISPLAY_REQUESTS:
+ return asFP<HWC2_PFN_GET_DISPLAY_REQUESTS>(getDisplayRequestsHook);
+ case HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES:
+ return asFP<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(acceptDisplayChangesHook);
+ case HWC2_FUNCTION_PRESENT_DISPLAY:
+ return asFP<HWC2_PFN_PRESENT_DISPLAY>(presentDisplayHook);
+ case HWC2_FUNCTION_GET_RELEASE_FENCES:
+ return asFP<HWC2_PFN_GET_RELEASE_FENCES>(getReleaseFencesHook);
+
+ // layer create/destroy
+ case HWC2_FUNCTION_CREATE_LAYER:
+ return asFP<HWC2_PFN_CREATE_LAYER>(createLayerHook);
+ case HWC2_FUNCTION_DESTROY_LAYER:
+ return asFP<HWC2_PFN_DESTROY_LAYER>(destroyLayerHook);
+
+ // layer functions; validateDisplay not required
+ case HWC2_FUNCTION_SET_CURSOR_POSITION:
+ return asFP<HWC2_PFN_SET_CURSOR_POSITION>(setCursorPositionHook);
+ case HWC2_FUNCTION_SET_LAYER_BUFFER:
+ return asFP<HWC2_PFN_SET_LAYER_BUFFER>(setLayerBufferHook);
+ case HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE:
+ return asFP<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(setLayerSurfaceDamageHook);
+
+ // layer state functions; validateDisplay required
+ case HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE:
+ return asFP<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(setLayerCompositionTypeHook);
+ case HWC2_FUNCTION_SET_LAYER_BLEND_MODE:
+ return asFP<HWC2_PFN_SET_LAYER_BLEND_MODE>(setLayerStateHook<int32_t>);
+ case HWC2_FUNCTION_SET_LAYER_COLOR:
+ return asFP<HWC2_PFN_SET_LAYER_COLOR>(setLayerStateHook<hwc_color_t>);
+ case HWC2_FUNCTION_SET_LAYER_DATASPACE:
+ return asFP<HWC2_PFN_SET_LAYER_DATASPACE>(setLayerStateHook<int32_t>);
+ case HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME:
+ return asFP<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(setLayerStateHook<hwc_rect_t>);
+ case HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA:
+ return asFP<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(setLayerStateHook<float>);
+ case HWC2_FUNCTION_SET_LAYER_SIDEBAND_STREAM:
+ return asFP<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(setLayerStateHook<buffer_handle_t>);
+ case HWC2_FUNCTION_SET_LAYER_SOURCE_CROP:
+ return asFP<HWC2_PFN_SET_LAYER_SOURCE_CROP>(setLayerStateHook<hwc_frect_t>);
+ case HWC2_FUNCTION_SET_LAYER_TRANSFORM:
+ return asFP<HWC2_PFN_SET_LAYER_TRANSFORM>(setLayerStateHook<int32_t>);
+ case HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION:
+ return asFP<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(setLayerStateHook<hwc_region_t>);
+ case HWC2_FUNCTION_SET_LAYER_Z_ORDER:
+ return asFP<HWC2_PFN_SET_LAYER_Z_ORDER>(setLayerStateHook<uint32_t>);
+
+ default:
+ ALOGE("unknown function descriptor %d", descriptor);
+ return nullptr;
+ }
+}
+
+void getCapabilitiesHook(hwc2_device_t* /*device*/, uint32_t* outCount,
+ int32_t* /*outCapabilities*/) {
+ *outCount = 0;
+}
+
+int closeHook(hw_device_t* device) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ adapter.close();
+ return 0;
+}
+
+} // anonymous namespace
+
+HWC2OnFbAdapter::HWC2OnFbAdapter(framebuffer_device_t* fbDevice)
+ : hwc2_device_t(), mFbDevice(fbDevice) {
+ common.close = closeHook;
+ hwc2_device::getCapabilities = getCapabilitiesHook;
+ hwc2_device::getFunction = getFunctionHook;
+
+ mFbInfo.name = "fbdev";
+ mFbInfo.width = mFbDevice->width;
+ mFbInfo.height = mFbDevice->height;
+ mFbInfo.format = mFbDevice->format;
+ mFbInfo.vsync_period_ns = int(1e9 / mFbDevice->fps);
+ mFbInfo.xdpi_scaled = int(mFbDevice->xdpi * 1000.0f);
+ mFbInfo.ydpi_scaled = int(mFbDevice->ydpi * 1000.0f);
+
+ mVsyncThread.start(0, mFbInfo.vsync_period_ns);
+}
+
+HWC2OnFbAdapter& HWC2OnFbAdapter::cast(hw_device_t* device) {
+ return *reinterpret_cast<HWC2OnFbAdapter*>(device);
+}
+
+HWC2OnFbAdapter& HWC2OnFbAdapter::cast(hwc2_device_t* device) {
+ return *reinterpret_cast<HWC2OnFbAdapter*>(device);
+}
+
+hwc2_display_t HWC2OnFbAdapter::getDisplayId() {
+ return 0;
+}
+
+hwc2_config_t HWC2OnFbAdapter::getConfigId() {
+ return 0;
+}
+
+void HWC2OnFbAdapter::close() {
+ mVsyncThread.stop();
+ framebuffer_close(mFbDevice);
+}
+
+const HWC2OnFbAdapter::Info& HWC2OnFbAdapter::getInfo() const {
+ return mFbInfo;
+}
+
+void HWC2OnFbAdapter::updateDebugString() {
+ if (mFbDevice->common.version >= 1 && mFbDevice->dump) {
+ char buffer[4096];
+ mFbDevice->dump(mFbDevice, buffer, sizeof(buffer));
+ buffer[sizeof(buffer) - 1] = '\0';
+
+ mDebugString = buffer;
+ }
+}
+
+const std::string& HWC2OnFbAdapter::getDebugString() const {
+ return mDebugString;
+}
+
+void HWC2OnFbAdapter::setState(State state) {
+ mState = state;
+}
+
+HWC2OnFbAdapter::State HWC2OnFbAdapter::getState() const {
+ return mState;
+}
+
+hwc2_layer_t HWC2OnFbAdapter::addLayer() {
+ hwc2_layer_t id = ++mNextLayerId;
+
+ mLayers.insert(id);
+ mDirtyLayers.insert(id);
+
+ return id;
+}
+
+bool HWC2OnFbAdapter::removeLayer(hwc2_layer_t layer) {
+ mDirtyLayers.erase(layer);
+ return mLayers.erase(layer);
+}
+
+bool HWC2OnFbAdapter::hasLayer(hwc2_layer_t layer) const {
+ return mLayers.count(layer) > 0;
+}
+
+bool HWC2OnFbAdapter::markLayerDirty(hwc2_layer_t layer, bool dirty) {
+ if (mLayers.count(layer) == 0) {
+ return false;
+ }
+
+ if (dirty) {
+ mDirtyLayers.insert(layer);
+ } else {
+ mDirtyLayers.erase(layer);
+ }
+
+ return true;
+}
+
+const std::unordered_set<hwc2_layer_t>& HWC2OnFbAdapter::getDirtyLayers() const {
+ return mDirtyLayers;
+}
+
+void HWC2OnFbAdapter::clearDirtyLayers() {
+ mDirtyLayers.clear();
+}
+
+/*
+ * For each frame, SurfaceFlinger
+ *
+ * - peforms GLES composition
+ * - calls eglSwapBuffers
+ * - calls setClientTarget, which maps to setBuffer below
+ * - calls presentDisplay, which maps to postBuffer below
+ *
+ * setBuffer should be a good place to call compositionComplete.
+ *
+ * As for post, it
+ *
+ * - schedules the buffer for presentation on the next vsync
+ * - locks the buffer and blocks all other users trying to lock it
+ *
+ * It does not give us a way to return a present fence, and we need to live
+ * with that. The implication is that, when we are double-buffered,
+ * SurfaceFlinger assumes the front buffer is available for rendering again
+ * immediately after the back buffer is posted. The locking semantics
+ * hopefully are strong enough that the rendering will be blocked.
+ */
+void HWC2OnFbAdapter::setBuffer(buffer_handle_t buffer) {
+ if (mFbDevice->compositionComplete) {
+ mFbDevice->compositionComplete(mFbDevice);
+ }
+ mBuffer = buffer;
+}
+
+bool HWC2OnFbAdapter::postBuffer() {
+ int error = 0;
+ if (mBuffer) {
+ error = mFbDevice->post(mFbDevice, mBuffer);
+ }
+
+ return error == 0;
+}
+
+void HWC2OnFbAdapter::setVsyncCallback(HWC2_PFN_VSYNC callback, hwc2_callback_data_t data) {
+ mVsyncThread.setCallback(callback, data);
+}
+
+void HWC2OnFbAdapter::enableVsync(bool enable) {
+ mVsyncThread.enableCallback(enable);
+}
+
+int64_t HWC2OnFbAdapter::VsyncThread::now() {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ return int64_t(ts.tv_sec) * 1'000'000'000 + ts.tv_nsec;
+}
+
+bool HWC2OnFbAdapter::VsyncThread::sleepUntil(int64_t t) {
+ struct timespec ts;
+ ts.tv_sec = t / 1'000'000'000;
+ ts.tv_nsec = t % 1'000'000'000;
+
+ while (true) {
+ int error = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, nullptr);
+ if (error) {
+ if (error == EINTR) {
+ continue;
+ }
+ return false;
+ } else {
+ return true;
+ }
+ }
+}
+
+void HWC2OnFbAdapter::VsyncThread::start(int64_t firstVsync, int64_t period) {
+ mNextVsync = firstVsync;
+ mPeriod = period;
+ mStarted = true;
+ mThread = std::thread(&VsyncThread::vsyncLoop, this);
+}
+
+void HWC2OnFbAdapter::VsyncThread::stop() {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mStarted = false;
+ }
+ mCondition.notify_all();
+ mThread.join();
+}
+
+void HWC2OnFbAdapter::VsyncThread::setCallback(HWC2_PFN_VSYNC callback, hwc2_callback_data_t data) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mCallback = callback;
+ mCallbackData = data;
+}
+
+void HWC2OnFbAdapter::VsyncThread::enableCallback(bool enable) {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mCallbackEnabled = enable;
+ }
+ mCondition.notify_all();
+}
+
+void HWC2OnFbAdapter::VsyncThread::vsyncLoop() {
+ prctl(PR_SET_NAME, "VsyncThread", 0, 0, 0);
+
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (!mStarted) {
+ return;
+ }
+
+ while (true) {
+ if (!mCallbackEnabled) {
+ mCondition.wait(lock, [this] { return mCallbackEnabled || !mStarted; });
+ if (!mStarted) {
+ break;
+ }
+ }
+
+ lock.unlock();
+
+ // adjust mNextVsync if necessary
+ int64_t t = now();
+ if (mNextVsync < t) {
+ int64_t n = (t - mNextVsync + mPeriod - 1) / mPeriod;
+ mNextVsync += mPeriod * n;
+ }
+ bool fire = sleepUntil(mNextVsync);
+
+ lock.lock();
+
+ if (fire) {
+ ALOGV("VsyncThread(%" PRId64 ")", mNextVsync);
+ if (mCallback) {
+ mCallback(mCallbackData, getDisplayId(), mNextVsync);
+ }
+ mNextVsync += mPeriod;
+ }
+ }
+}
+
+} // namespace android
diff --git a/graphics/composer/2.1/utils/hwc2onfbadapter/include/hwc2onfbadapter/HWC2OnFbAdapter.h b/graphics/composer/2.1/utils/hwc2onfbadapter/include/hwc2onfbadapter/HWC2OnFbAdapter.h
new file mode 100644
index 0000000..d6272fd
--- /dev/null
+++ b/graphics/composer/2.1/utils/hwc2onfbadapter/include/hwc2onfbadapter/HWC2OnFbAdapter.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#ifndef ANDROID_SF_HWC2_ON_FB_ADAPTER_H
+#define ANDROID_SF_HWC2_ON_FB_ADAPTER_H
+
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <thread>
+#include <unordered_set>
+
+#include <hardware/hwcomposer2.h>
+
+struct framebuffer_device_t;
+
+namespace android {
+
+class HWC2OnFbAdapter : public hwc2_device_t {
+public:
+ HWC2OnFbAdapter(framebuffer_device_t* fbDevice);
+
+ static HWC2OnFbAdapter& cast(hw_device_t* device);
+ static HWC2OnFbAdapter& cast(hwc2_device_t* device);
+
+ static hwc2_display_t getDisplayId();
+ static hwc2_config_t getConfigId();
+
+ void close();
+
+ struct Info {
+ std::string name;
+ uint32_t width;
+ uint32_t height;
+ int format;
+ int vsync_period_ns;
+ int xdpi_scaled;
+ int ydpi_scaled;
+ };
+ const Info& getInfo() const;
+
+ void updateDebugString();
+ const std::string& getDebugString() const;
+
+ enum class State {
+ MODIFIED,
+ VALIDATED_WITH_CHANGES,
+ VALIDATED,
+ };
+ void setState(State state);
+ State getState() const;
+
+ hwc2_layer_t addLayer();
+ bool removeLayer(hwc2_layer_t layer);
+ bool hasLayer(hwc2_layer_t layer) const;
+ bool markLayerDirty(hwc2_layer_t layer, bool dirty);
+ const std::unordered_set<hwc2_layer_t>& getDirtyLayers() const;
+ void clearDirtyLayers();
+
+ void setBuffer(buffer_handle_t buffer);
+ bool postBuffer();
+
+ void setVsyncCallback(HWC2_PFN_VSYNC callback, hwc2_callback_data_t data);
+ void enableVsync(bool enable);
+
+private:
+ framebuffer_device_t* mFbDevice{nullptr};
+ Info mFbInfo{};
+
+ std::string mDebugString;
+
+ State mState{State::MODIFIED};
+
+ uint64_t mNextLayerId{0};
+ std::unordered_set<hwc2_layer_t> mLayers;
+ std::unordered_set<hwc2_layer_t> mDirtyLayers;
+
+ buffer_handle_t mBuffer{nullptr};
+
+ class VsyncThread {
+ public:
+ static int64_t now();
+ static bool sleepUntil(int64_t t);
+
+ void start(int64_t first, int64_t period);
+ void stop();
+ void setCallback(HWC2_PFN_VSYNC callback, hwc2_callback_data_t data);
+ void enableCallback(bool enable);
+
+ private:
+ void vsyncLoop();
+ bool waitUntilNextVsync();
+
+ std::thread mThread;
+ int64_t mNextVsync{0};
+ int64_t mPeriod{0};
+
+ std::mutex mMutex;
+ std::condition_variable mCondition;
+ bool mStarted{false};
+ HWC2_PFN_VSYNC mCallback{nullptr};
+ hwc2_callback_data_t mCallbackData{nullptr};
+ bool mCallbackEnabled{false};
+ };
+ VsyncThread mVsyncThread;
+};
+
+} // namespace android
+
+#endif // ANDROID_SF_HWC2_ON_FB_ADAPTER_H
diff --git a/graphics/composer/2.1/utils/passthrough/Android.bp b/graphics/composer/2.1/utils/passthrough/Android.bp
new file mode 100644
index 0000000..4d3c976
--- /dev/null
+++ b/graphics/composer/2.1/utils/passthrough/Android.bp
@@ -0,0 +1,22 @@
+cc_library_headers {
+ name: "android.hardware.graphics.composer@2.1-passthrough",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ shared_libs: [
+ "libhardware",
+ "libhwc2on1adapter",
+ "libhwc2onfbadapter",
+ ],
+ export_shared_lib_headers: [
+ "libhardware",
+ "libhwc2on1adapter",
+ "libhwc2onfbadapter",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-hal",
+ ],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.1-hal",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcHal.h b/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcHal.h
new file mode 100644
index 0000000..964e75b
--- /dev/null
+++ b/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcHal.h
@@ -0,0 +1,670 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "HwcHal.h included without LOG_TAG"
+#endif
+
+#include <atomic>
+#include <cstring> // for strerror
+#include <type_traits>
+#include <unordered_set>
+#include <vector>
+
+#include <android/hardware/graphics/composer/2.1/IComposer.h>
+#include <composer-hal/2.1/ComposerHal.h>
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace passthrough {
+
+namespace detail {
+
+using android::hardware::graphics::common::V1_0::ColorMode;
+using android::hardware::graphics::common::V1_0::ColorTransform;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::Hdr;
+using android::hardware::graphics::common::V1_0::PixelFormat;
+using android::hardware::graphics::common::V1_0::Transform;
+
+// HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2
+template <typename Hal>
+class HwcHalImpl : public Hal {
+ public:
+ virtual ~HwcHalImpl() {
+ if (mDevice) {
+ hwc2_close(mDevice);
+ }
+ }
+
+ bool initWithModule(const hw_module_t* module) {
+ hwc2_device_t* device;
+ int result = hwc2_open(module, &device);
+ if (result) {
+ ALOGE("failed to open hwcomposer2 device: %s", strerror(-result));
+ return false;
+ }
+
+ return initWithDevice(std::move(device), true);
+ }
+
+ bool initWithDevice(hwc2_device_t* device, bool requireReliablePresentFence) {
+ // we own the device from this point on
+ mDevice = device;
+
+ initCapabilities();
+ if (requireReliablePresentFence &&
+ hasCapability(HWC2_CAPABILITY_PRESENT_FENCE_IS_NOT_RELIABLE)) {
+ ALOGE("present fence must be reliable");
+ mDevice->common.close(&mDevice->common);
+ mDevice = nullptr;
+ return false;
+ }
+
+ if (!initDispatch()) {
+ mDevice->common.close(&mDevice->common);
+ mDevice = nullptr;
+ return false;
+ }
+
+ return true;
+ }
+
+ bool hasCapability(hwc2_capability_t capability) override {
+ return (mCapabilities.count(capability) > 0);
+ }
+
+ std::string dumpDebugInfo() override {
+ uint32_t len = 0;
+ mDispatch.dump(mDevice, &len, nullptr);
+
+ std::vector<char> buf(len + 1);
+ mDispatch.dump(mDevice, &len, buf.data());
+ buf.resize(len + 1);
+ buf[len] = '\0';
+
+ return buf.data();
+ }
+
+ void registerEventCallback(hal::ComposerHal::EventCallback* callback) override {
+ mMustValidateDisplay = true;
+ mEventCallback = callback;
+
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this,
+ reinterpret_cast<hwc2_function_pointer_t>(hotplugHook));
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this,
+ reinterpret_cast<hwc2_function_pointer_t>(refreshHook));
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this,
+ reinterpret_cast<hwc2_function_pointer_t>(vsyncHook));
+ }
+
+ void unregisterEventCallback() override {
+ // we assume the callback functions
+ //
+ // - can be unregistered
+ // - can be in-flight
+ // - will never be called afterward
+ //
+ // which is likely incorrect
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this, nullptr);
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this, nullptr);
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this, nullptr);
+
+ mEventCallback = nullptr;
+ }
+
+ uint32_t getMaxVirtualDisplayCount() override {
+ return mDispatch.getMaxVirtualDisplayCount(mDevice);
+ }
+
+ Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
+ Display* outDisplay) override {
+ int32_t hwc_format = static_cast<int32_t>(*format);
+ int32_t err =
+ mDispatch.createVirtualDisplay(mDevice, width, height, &hwc_format, outDisplay);
+ *format = static_cast<PixelFormat>(hwc_format);
+
+ return static_cast<Error>(err);
+ }
+
+ Error destroyVirtualDisplay(Display display) override {
+ int32_t err = mDispatch.destroyVirtualDisplay(mDevice, display);
+ return static_cast<Error>(err);
+ }
+
+ Error createLayer(Display display, Layer* outLayer) override {
+ int32_t err = mDispatch.createLayer(mDevice, display, outLayer);
+ return static_cast<Error>(err);
+ }
+
+ Error destroyLayer(Display display, Layer layer) override {
+ int32_t err = mDispatch.destroyLayer(mDevice, display, layer);
+ return static_cast<Error>(err);
+ }
+
+ Error getActiveConfig(Display display, Config* outConfig) override {
+ int32_t err = mDispatch.getActiveConfig(mDevice, display, outConfig);
+ return static_cast<Error>(err);
+ }
+
+ Error getClientTargetSupport(Display display, uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace) override {
+ int32_t err = mDispatch.getClientTargetSupport(mDevice, display, width, height,
+ static_cast<int32_t>(format),
+ static_cast<int32_t>(dataspace));
+ return static_cast<Error>(err);
+ }
+
+ Error getColorModes(Display display, hidl_vec<ColorMode>* outModes) override {
+ uint32_t count = 0;
+ int32_t err = mDispatch.getColorModes(mDevice, display, &count, nullptr);
+ if (err != HWC2_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+
+ outModes->resize(count);
+ err = mDispatch.getColorModes(
+ mDevice, display, &count,
+ reinterpret_cast<std::underlying_type<ColorMode>::type*>(outModes->data()));
+ if (err != HWC2_ERROR_NONE) {
+ *outModes = hidl_vec<ColorMode>();
+ return static_cast<Error>(err);
+ }
+
+ return Error::NONE;
+ }
+
+ Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute,
+ int32_t* outValue) override {
+ int32_t err = mDispatch.getDisplayAttribute(mDevice, display, config,
+ static_cast<int32_t>(attribute), outValue);
+ return static_cast<Error>(err);
+ }
+
+ Error getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) override {
+ uint32_t count = 0;
+ int32_t err = mDispatch.getDisplayConfigs(mDevice, display, &count, nullptr);
+ if (err != HWC2_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+
+ outConfigs->resize(count);
+ err = mDispatch.getDisplayConfigs(mDevice, display, &count, outConfigs->data());
+ if (err != HWC2_ERROR_NONE) {
+ *outConfigs = hidl_vec<Config>();
+ return static_cast<Error>(err);
+ }
+
+ return Error::NONE;
+ }
+
+ Error getDisplayName(Display display, hidl_string* outName) override {
+ uint32_t count = 0;
+ int32_t err = mDispatch.getDisplayName(mDevice, display, &count, nullptr);
+ if (err != HWC2_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+
+ std::vector<char> buf(count + 1);
+ err = mDispatch.getDisplayName(mDevice, display, &count, buf.data());
+ if (err != HWC2_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+ buf.resize(count + 1);
+ buf[count] = '\0';
+
+ *outName = buf.data();
+
+ return Error::NONE;
+ }
+
+ Error getDisplayType(Display display, IComposerClient::DisplayType* outType) override {
+ int32_t hwc_type = HWC2_DISPLAY_TYPE_INVALID;
+ int32_t err = mDispatch.getDisplayType(mDevice, display, &hwc_type);
+ *outType = static_cast<IComposerClient::DisplayType>(hwc_type);
+
+ return static_cast<Error>(err);
+ }
+
+ Error getDozeSupport(Display display, bool* outSupport) override {
+ int32_t hwc_support = 0;
+ int32_t err = mDispatch.getDozeSupport(mDevice, display, &hwc_support);
+ *outSupport = hwc_support;
+
+ return static_cast<Error>(err);
+ }
+
+ Error getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes, float* outMaxLuminance,
+ float* outMaxAverageLuminance, float* outMinLuminance) override {
+ uint32_t count = 0;
+ int32_t err =
+ mDispatch.getHdrCapabilities(mDevice, display, &count, nullptr, outMaxLuminance,
+ outMaxAverageLuminance, outMinLuminance);
+ if (err != HWC2_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+
+ outTypes->resize(count);
+ err = mDispatch.getHdrCapabilities(
+ mDevice, display, &count,
+ reinterpret_cast<std::underlying_type<Hdr>::type*>(outTypes->data()), outMaxLuminance,
+ outMaxAverageLuminance, outMinLuminance);
+ if (err != HWC2_ERROR_NONE) {
+ *outTypes = hidl_vec<Hdr>();
+ return static_cast<Error>(err);
+ }
+
+ return Error::NONE;
+ }
+
+ Error setActiveConfig(Display display, Config config) override {
+ int32_t err = mDispatch.setActiveConfig(mDevice, display, config);
+ return static_cast<Error>(err);
+ }
+
+ Error setColorMode(Display display, ColorMode mode) override {
+ int32_t err = mDispatch.setColorMode(mDevice, display, static_cast<int32_t>(mode));
+ return static_cast<Error>(err);
+ }
+
+ Error setPowerMode(Display display, IComposerClient::PowerMode mode) override {
+ int32_t err = mDispatch.setPowerMode(mDevice, display, static_cast<int32_t>(mode));
+ return static_cast<Error>(err);
+ }
+
+ Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override {
+ int32_t err = mDispatch.setVsyncEnabled(mDevice, display, static_cast<int32_t>(enabled));
+ return static_cast<Error>(err);
+ }
+
+ Error setColorTransform(Display display, const float* matrix, int32_t hint) override {
+ int32_t err = mDispatch.setColorTransform(mDevice, display, matrix, hint);
+ return static_cast<Error>(err);
+ }
+
+ Error setClientTarget(Display display, buffer_handle_t target, int32_t acquireFence,
+ int32_t dataspace, const std::vector<hwc_rect_t>& damage) override {
+ hwc_region region = {damage.size(), damage.data()};
+ int32_t err =
+ mDispatch.setClientTarget(mDevice, display, target, acquireFence, dataspace, region);
+ return static_cast<Error>(err);
+ }
+
+ Error setOutputBuffer(Display display, buffer_handle_t buffer, int32_t releaseFence) override {
+ int32_t err = mDispatch.setOutputBuffer(mDevice, display, buffer, releaseFence);
+ // unlike in setClientTarget, releaseFence is owned by us
+ if (err == HWC2_ERROR_NONE && releaseFence >= 0) {
+ close(releaseFence);
+ }
+
+ return static_cast<Error>(err);
+ }
+
+ Error validateDisplay(Display display, std::vector<Layer>* outChangedLayers,
+ std::vector<IComposerClient::Composition>* outCompositionTypes,
+ uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
+ std::vector<uint32_t>* outRequestMasks) override {
+ uint32_t typesCount = 0;
+ uint32_t reqsCount = 0;
+ int32_t err = mDispatch.validateDisplay(mDevice, display, &typesCount, &reqsCount);
+ mMustValidateDisplay = false;
+
+ if (err != HWC2_ERROR_NONE && err != HWC2_ERROR_HAS_CHANGES) {
+ return static_cast<Error>(err);
+ }
+
+ err = mDispatch.getChangedCompositionTypes(mDevice, display, &typesCount, nullptr, nullptr);
+ if (err != HWC2_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+
+ std::vector<Layer> changedLayers(typesCount);
+ std::vector<IComposerClient::Composition> compositionTypes(typesCount);
+ err = mDispatch.getChangedCompositionTypes(
+ mDevice, display, &typesCount, changedLayers.data(),
+ reinterpret_cast<std::underlying_type<IComposerClient::Composition>::type*>(
+ compositionTypes.data()));
+ if (err != HWC2_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+
+ int32_t displayReqs = 0;
+ err = mDispatch.getDisplayRequests(mDevice, display, &displayReqs, &reqsCount, nullptr,
+ nullptr);
+ if (err != HWC2_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+
+ std::vector<Layer> requestedLayers(reqsCount);
+ std::vector<uint32_t> requestMasks(reqsCount);
+ err = mDispatch.getDisplayRequests(mDevice, display, &displayReqs, &reqsCount,
+ requestedLayers.data(),
+ reinterpret_cast<int32_t*>(requestMasks.data()));
+ if (err != HWC2_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+
+ *outChangedLayers = std::move(changedLayers);
+ *outCompositionTypes = std::move(compositionTypes);
+ *outDisplayRequestMask = displayReqs;
+ *outRequestedLayers = std::move(requestedLayers);
+ *outRequestMasks = std::move(requestMasks);
+
+ return static_cast<Error>(err);
+ }
+
+ Error acceptDisplayChanges(Display display) override {
+ int32_t err = mDispatch.acceptDisplayChanges(mDevice, display);
+ return static_cast<Error>(err);
+ }
+
+ Error presentDisplay(Display display, int32_t* outPresentFence, std::vector<Layer>* outLayers,
+ std::vector<int32_t>* outReleaseFences) override {
+ if (mMustValidateDisplay) {
+ return Error::NOT_VALIDATED;
+ }
+
+ *outPresentFence = -1;
+ int32_t err = mDispatch.presentDisplay(mDevice, display, outPresentFence);
+ if (err != HWC2_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+
+ uint32_t count = 0;
+ err = mDispatch.getReleaseFences(mDevice, display, &count, nullptr, nullptr);
+ if (err != HWC2_ERROR_NONE) {
+ ALOGW("failed to get release fences");
+ return Error::NONE;
+ }
+
+ outLayers->resize(count);
+ outReleaseFences->resize(count);
+ err = mDispatch.getReleaseFences(mDevice, display, &count, outLayers->data(),
+ outReleaseFences->data());
+ if (err != HWC2_ERROR_NONE) {
+ ALOGW("failed to get release fences");
+ outLayers->clear();
+ outReleaseFences->clear();
+ return Error::NONE;
+ }
+
+ return static_cast<Error>(err);
+ }
+
+ Error setLayerCursorPosition(Display display, Layer layer, int32_t x, int32_t y) override {
+ int32_t err = mDispatch.setCursorPosition(mDevice, display, layer, x, y);
+ return static_cast<Error>(err);
+ }
+
+ Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer,
+ int32_t acquireFence) override {
+ int32_t err = mDispatch.setLayerBuffer(mDevice, display, layer, buffer, acquireFence);
+ return static_cast<Error>(err);
+ }
+
+ Error setLayerSurfaceDamage(Display display, Layer layer,
+ const std::vector<hwc_rect_t>& damage) override {
+ hwc_region region = {damage.size(), damage.data()};
+ int32_t err = mDispatch.setLayerSurfaceDamage(mDevice, display, layer, region);
+ return static_cast<Error>(err);
+ }
+
+ Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override {
+ int32_t err = mDispatch.setLayerBlendMode(mDevice, display, layer, mode);
+ return static_cast<Error>(err);
+ }
+
+ Error setLayerColor(Display display, Layer layer, IComposerClient::Color color) override {
+ hwc_color_t hwc_color{color.r, color.g, color.b, color.a};
+ int32_t err = mDispatch.setLayerColor(mDevice, display, layer, hwc_color);
+ return static_cast<Error>(err);
+ }
+
+ Error setLayerCompositionType(Display display, Layer layer, int32_t type) override {
+ int32_t err = mDispatch.setLayerCompositionType(mDevice, display, layer, type);
+ return static_cast<Error>(err);
+ }
+
+ Error setLayerDataspace(Display display, Layer layer, int32_t dataspace) override {
+ int32_t err = mDispatch.setLayerDataspace(mDevice, display, layer, dataspace);
+ return static_cast<Error>(err);
+ }
+
+ Error setLayerDisplayFrame(Display display, Layer layer, const hwc_rect_t& frame) override {
+ int32_t err = mDispatch.setLayerDisplayFrame(mDevice, display, layer, frame);
+ return static_cast<Error>(err);
+ }
+
+ Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override {
+ int32_t err = mDispatch.setLayerPlaneAlpha(mDevice, display, layer, alpha);
+ return static_cast<Error>(err);
+ }
+
+ Error setLayerSidebandStream(Display display, Layer layer, buffer_handle_t stream) override {
+ int32_t err = mDispatch.setLayerSidebandStream(mDevice, display, layer, stream);
+ return static_cast<Error>(err);
+ }
+
+ Error setLayerSourceCrop(Display display, Layer layer, const hwc_frect_t& crop) override {
+ int32_t err = mDispatch.setLayerSourceCrop(mDevice, display, layer, crop);
+ return static_cast<Error>(err);
+ }
+
+ Error setLayerTransform(Display display, Layer layer, int32_t transform) override {
+ int32_t err = mDispatch.setLayerTransform(mDevice, display, layer, transform);
+ return static_cast<Error>(err);
+ }
+
+ Error setLayerVisibleRegion(Display display, Layer layer,
+ const std::vector<hwc_rect_t>& visible) override {
+ hwc_region_t region = {visible.size(), visible.data()};
+ int32_t err = mDispatch.setLayerVisibleRegion(mDevice, display, layer, region);
+ return static_cast<Error>(err);
+ }
+
+ Error setLayerZOrder(Display display, Layer layer, uint32_t z) override {
+ int32_t err = mDispatch.setLayerZOrder(mDevice, display, layer, z);
+ return static_cast<Error>(err);
+ }
+
+ protected:
+ virtual void initCapabilities() {
+ uint32_t count = 0;
+ mDevice->getCapabilities(mDevice, &count, nullptr);
+
+ std::vector<int32_t> caps(count);
+ mDevice->getCapabilities(mDevice, &count, caps.data());
+ caps.resize(count);
+
+ mCapabilities.reserve(count);
+ for (auto cap : caps) {
+ mCapabilities.insert(static_cast<hwc2_capability_t>(cap));
+ }
+ }
+
+ template <typename T>
+ bool initDispatch(hwc2_function_descriptor_t desc, T* outPfn) {
+ auto pfn = mDevice->getFunction(mDevice, desc);
+ if (pfn) {
+ *outPfn = reinterpret_cast<T>(pfn);
+ return true;
+ } else {
+ ALOGE("failed to get hwcomposer2 function %d", desc);
+ return false;
+ }
+ }
+
+ virtual bool initDispatch() {
+ if (!initDispatch(HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES, &mDispatch.acceptDisplayChanges) ||
+ !initDispatch(HWC2_FUNCTION_CREATE_LAYER, &mDispatch.createLayer) ||
+ !initDispatch(HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY, &mDispatch.createVirtualDisplay) ||
+ !initDispatch(HWC2_FUNCTION_DESTROY_LAYER, &mDispatch.destroyLayer) ||
+ !initDispatch(HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY,
+ &mDispatch.destroyVirtualDisplay) ||
+ !initDispatch(HWC2_FUNCTION_DUMP, &mDispatch.dump) ||
+ !initDispatch(HWC2_FUNCTION_GET_ACTIVE_CONFIG, &mDispatch.getActiveConfig) ||
+ !initDispatch(HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES,
+ &mDispatch.getChangedCompositionTypes) ||
+ !initDispatch(HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT,
+ &mDispatch.getClientTargetSupport) ||
+ !initDispatch(HWC2_FUNCTION_GET_COLOR_MODES, &mDispatch.getColorModes) ||
+ !initDispatch(HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE, &mDispatch.getDisplayAttribute) ||
+ !initDispatch(HWC2_FUNCTION_GET_DISPLAY_CONFIGS, &mDispatch.getDisplayConfigs) ||
+ !initDispatch(HWC2_FUNCTION_GET_DISPLAY_NAME, &mDispatch.getDisplayName) ||
+ !initDispatch(HWC2_FUNCTION_GET_DISPLAY_REQUESTS, &mDispatch.getDisplayRequests) ||
+ !initDispatch(HWC2_FUNCTION_GET_DISPLAY_TYPE, &mDispatch.getDisplayType) ||
+ !initDispatch(HWC2_FUNCTION_GET_DOZE_SUPPORT, &mDispatch.getDozeSupport) ||
+ !initDispatch(HWC2_FUNCTION_GET_HDR_CAPABILITIES, &mDispatch.getHdrCapabilities) ||
+ !initDispatch(HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT,
+ &mDispatch.getMaxVirtualDisplayCount) ||
+ !initDispatch(HWC2_FUNCTION_GET_RELEASE_FENCES, &mDispatch.getReleaseFences) ||
+ !initDispatch(HWC2_FUNCTION_PRESENT_DISPLAY, &mDispatch.presentDisplay) ||
+ !initDispatch(HWC2_FUNCTION_REGISTER_CALLBACK, &mDispatch.registerCallback) ||
+ !initDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG, &mDispatch.setActiveConfig) ||
+ !initDispatch(HWC2_FUNCTION_SET_CLIENT_TARGET, &mDispatch.setClientTarget) ||
+ !initDispatch(HWC2_FUNCTION_SET_COLOR_MODE, &mDispatch.setColorMode) ||
+ !initDispatch(HWC2_FUNCTION_SET_COLOR_TRANSFORM, &mDispatch.setColorTransform) ||
+ !initDispatch(HWC2_FUNCTION_SET_CURSOR_POSITION, &mDispatch.setCursorPosition) ||
+ !initDispatch(HWC2_FUNCTION_SET_LAYER_BLEND_MODE, &mDispatch.setLayerBlendMode) ||
+ !initDispatch(HWC2_FUNCTION_SET_LAYER_BUFFER, &mDispatch.setLayerBuffer) ||
+ !initDispatch(HWC2_FUNCTION_SET_LAYER_COLOR, &mDispatch.setLayerColor) ||
+ !initDispatch(HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE,
+ &mDispatch.setLayerCompositionType) ||
+ !initDispatch(HWC2_FUNCTION_SET_LAYER_DATASPACE, &mDispatch.setLayerDataspace) ||
+ !initDispatch(HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME, &mDispatch.setLayerDisplayFrame) ||
+ !initDispatch(HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA, &mDispatch.setLayerPlaneAlpha)) {
+ return false;
+ }
+
+ if (hasCapability(HWC2_CAPABILITY_SIDEBAND_STREAM)) {
+ if (!initDispatch(HWC2_FUNCTION_SET_LAYER_SIDEBAND_STREAM,
+ &mDispatch.setLayerSidebandStream)) {
+ return false;
+ }
+ }
+
+ if (!initDispatch(HWC2_FUNCTION_SET_LAYER_SOURCE_CROP, &mDispatch.setLayerSourceCrop) ||
+ !initDispatch(HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE,
+ &mDispatch.setLayerSurfaceDamage) ||
+ !initDispatch(HWC2_FUNCTION_SET_LAYER_TRANSFORM, &mDispatch.setLayerTransform) ||
+ !initDispatch(HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION,
+ &mDispatch.setLayerVisibleRegion) ||
+ !initDispatch(HWC2_FUNCTION_SET_LAYER_Z_ORDER, &mDispatch.setLayerZOrder) ||
+ !initDispatch(HWC2_FUNCTION_SET_OUTPUT_BUFFER, &mDispatch.setOutputBuffer) ||
+ !initDispatch(HWC2_FUNCTION_SET_POWER_MODE, &mDispatch.setPowerMode) ||
+ !initDispatch(HWC2_FUNCTION_SET_VSYNC_ENABLED, &mDispatch.setVsyncEnabled) ||
+ !initDispatch(HWC2_FUNCTION_VALIDATE_DISPLAY, &mDispatch.validateDisplay)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ static void hotplugHook(hwc2_callback_data_t callbackData, hwc2_display_t display,
+ int32_t connected) {
+ auto hal = static_cast<HwcHalImpl*>(callbackData);
+ hal->mEventCallback->onHotplug(display,
+ static_cast<IComposerCallback::Connection>(connected));
+ }
+
+ static void refreshHook(hwc2_callback_data_t callbackData, hwc2_display_t display) {
+ auto hal = static_cast<HwcHalImpl*>(callbackData);
+ hal->mMustValidateDisplay = true;
+ hal->mEventCallback->onRefresh(display);
+ }
+
+ static void vsyncHook(hwc2_callback_data_t callbackData, hwc2_display_t display,
+ int64_t timestamp) {
+ auto hal = static_cast<HwcHalImpl*>(callbackData);
+ hal->mEventCallback->onVsync(display, timestamp);
+ }
+
+ hwc2_device_t* mDevice = nullptr;
+
+ std::unordered_set<hwc2_capability_t> mCapabilities;
+
+ struct {
+ HWC2_PFN_ACCEPT_DISPLAY_CHANGES acceptDisplayChanges;
+ HWC2_PFN_CREATE_LAYER createLayer;
+ HWC2_PFN_CREATE_VIRTUAL_DISPLAY createVirtualDisplay;
+ HWC2_PFN_DESTROY_LAYER destroyLayer;
+ HWC2_PFN_DESTROY_VIRTUAL_DISPLAY destroyVirtualDisplay;
+ HWC2_PFN_DUMP dump;
+ HWC2_PFN_GET_ACTIVE_CONFIG getActiveConfig;
+ HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES getChangedCompositionTypes;
+ HWC2_PFN_GET_CLIENT_TARGET_SUPPORT getClientTargetSupport;
+ HWC2_PFN_GET_COLOR_MODES getColorModes;
+ HWC2_PFN_GET_DISPLAY_ATTRIBUTE getDisplayAttribute;
+ HWC2_PFN_GET_DISPLAY_CONFIGS getDisplayConfigs;
+ HWC2_PFN_GET_DISPLAY_NAME getDisplayName;
+ HWC2_PFN_GET_DISPLAY_REQUESTS getDisplayRequests;
+ HWC2_PFN_GET_DISPLAY_TYPE getDisplayType;
+ HWC2_PFN_GET_DOZE_SUPPORT getDozeSupport;
+ HWC2_PFN_GET_HDR_CAPABILITIES getHdrCapabilities;
+ HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT getMaxVirtualDisplayCount;
+ HWC2_PFN_GET_RELEASE_FENCES getReleaseFences;
+ HWC2_PFN_PRESENT_DISPLAY presentDisplay;
+ HWC2_PFN_REGISTER_CALLBACK registerCallback;
+ HWC2_PFN_SET_ACTIVE_CONFIG setActiveConfig;
+ HWC2_PFN_SET_CLIENT_TARGET setClientTarget;
+ HWC2_PFN_SET_COLOR_MODE setColorMode;
+ HWC2_PFN_SET_COLOR_TRANSFORM setColorTransform;
+ HWC2_PFN_SET_CURSOR_POSITION setCursorPosition;
+ HWC2_PFN_SET_LAYER_BLEND_MODE setLayerBlendMode;
+ HWC2_PFN_SET_LAYER_BUFFER setLayerBuffer;
+ HWC2_PFN_SET_LAYER_COLOR setLayerColor;
+ HWC2_PFN_SET_LAYER_COMPOSITION_TYPE setLayerCompositionType;
+ HWC2_PFN_SET_LAYER_DATASPACE setLayerDataspace;
+ HWC2_PFN_SET_LAYER_DISPLAY_FRAME setLayerDisplayFrame;
+ HWC2_PFN_SET_LAYER_PLANE_ALPHA setLayerPlaneAlpha;
+ HWC2_PFN_SET_LAYER_SIDEBAND_STREAM setLayerSidebandStream;
+ HWC2_PFN_SET_LAYER_SOURCE_CROP setLayerSourceCrop;
+ HWC2_PFN_SET_LAYER_SURFACE_DAMAGE setLayerSurfaceDamage;
+ HWC2_PFN_SET_LAYER_TRANSFORM setLayerTransform;
+ HWC2_PFN_SET_LAYER_VISIBLE_REGION setLayerVisibleRegion;
+ HWC2_PFN_SET_LAYER_Z_ORDER setLayerZOrder;
+ HWC2_PFN_SET_OUTPUT_BUFFER setOutputBuffer;
+ HWC2_PFN_SET_POWER_MODE setPowerMode;
+ HWC2_PFN_SET_VSYNC_ENABLED setVsyncEnabled;
+ HWC2_PFN_VALIDATE_DISPLAY validateDisplay;
+ } mDispatch = {};
+
+ hal::ComposerHal::EventCallback* mEventCallback = nullptr;
+
+ std::atomic<bool> mMustValidateDisplay{true};
+};
+
+} // namespace detail
+
+using HwcHal = detail::HwcHalImpl<hal::ComposerHal>;
+
+} // namespace passthrough
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcLoader.h b/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcLoader.h
new file mode 100644
index 0000000..33c914d
--- /dev/null
+++ b/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcLoader.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "HwcLoader.h included without LOG_TAG"
+#endif
+
+#include <memory>
+
+#include <composer-hal/2.1/Composer.h>
+#include <composer-passthrough/2.1/HwcHal.h>
+#include <hardware/fb.h>
+#include <hardware/gralloc.h>
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
+#include <hardware/hwcomposer2.h>
+#include <hwc2on1adapter/HWC2On1Adapter.h>
+#include <hwc2onfbadapter/HWC2OnFbAdapter.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace passthrough {
+
+class HwcLoader {
+ public:
+ static IComposer* load() {
+ const hw_module_t* module = loadModule();
+ if (!module) {
+ return nullptr;
+ }
+
+ auto hal = createHalWithAdapter(module);
+ if (!hal) {
+ return nullptr;
+ }
+
+ return createComposer(std::move(hal));
+ }
+
+ // load hwcomposer2 module
+ static const hw_module_t* loadModule() {
+ const hw_module_t* module;
+ int error = hw_get_module(HWC_HARDWARE_MODULE_ID, &module);
+ if (error) {
+ ALOGI("falling back to gralloc module");
+ error = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ }
+
+ if (error) {
+ ALOGE("failed to get hwcomposer or gralloc module");
+ return nullptr;
+ }
+
+ return module;
+ }
+
+ // create a ComposerHal instance
+ static std::unique_ptr<hal::ComposerHal> createHal(const hw_module_t* module) {
+ auto hal = std::make_unique<HwcHal>();
+ return hal->initWithModule(module) ? std::move(hal) : nullptr;
+ }
+
+ // create a ComposerHal instance, insert an adapter if necessary
+ static std::unique_ptr<hal::ComposerHal> createHalWithAdapter(const hw_module_t* module) {
+ bool adapted;
+ hwc2_device_t* device = openDeviceWithAdapter(module, &adapted);
+ if (!device) {
+ return nullptr;
+ }
+ auto hal = std::make_unique<HwcHal>();
+ return hal->initWithDevice(std::move(device), !adapted) ? std::move(hal) : nullptr;
+ }
+
+ // create an IComposer instance
+ static IComposer* createComposer(std::unique_ptr<hal::ComposerHal> hal) {
+ return hal::Composer::create(std::move(hal)).release();
+ }
+
+ protected:
+ // open hwcomposer2 device, install an adapter if necessary
+ static hwc2_device_t* openDeviceWithAdapter(const hw_module_t* module, bool* outAdapted) {
+ if (module->id && std::string(module->id) == GRALLOC_HARDWARE_MODULE_ID) {
+ *outAdapted = true;
+ return adaptGrallocModule(module);
+ }
+
+ hw_device_t* device;
+ int error = module->methods->open(module, HWC_HARDWARE_COMPOSER, &device);
+ if (error) {
+ ALOGE("failed to open hwcomposer device: %s", strerror(-error));
+ return nullptr;
+ }
+
+ int major = (device->version >> 24) & 0xf;
+ if (major != 2) {
+ *outAdapted = true;
+ return adaptHwc1Device(std::move(reinterpret_cast<hwc_composer_device_1*>(device)));
+ }
+
+ *outAdapted = false;
+ return reinterpret_cast<hwc2_device_t*>(device);
+ }
+
+ private:
+ static hwc2_device_t* adaptGrallocModule(const hw_module_t* module) {
+ framebuffer_device_t* device;
+ int error = framebuffer_open(module, &device);
+ if (error) {
+ ALOGE("failed to open framebuffer device: %s", strerror(-error));
+ return nullptr;
+ }
+
+ return new HWC2OnFbAdapter(device);
+ }
+
+ static hwc2_device_t* adaptHwc1Device(hwc_composer_device_1* device) {
+ int minor = (device->common.version >> 16) & 0xf;
+ if (minor < 1) {
+ ALOGE("hwcomposer 1.0 is not supported");
+ device->common.close(&device->common);
+ return nullptr;
+ }
+
+ return new HWC2On1Adapter(device);
+ }
+};
+
+} // namespace passthrough
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp
new file mode 100644
index 0000000..846cfdf
--- /dev/null
+++ b/graphics/composer/2.1/utils/vts/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_library_static {
+ name: "android.hardware.graphics.composer@2.1-vts",
+ defaults: ["hidl_defaults"],
+ srcs: [
+ "ComposerVts.cpp",
+ "GraphicsComposerCallback.cpp",
+ "TestCommandReader.cpp",
+ ],
+ static_libs: [
+ "VtsHalHidlTargetTestBase",
+ "android.hardware.graphics.composer@2.1",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ ],
+ cflags: [
+ "-O0",
+ "-g",
+ "-DLOG_TAG=\"ComposerVts\"",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
new file mode 100644
index 0000000..2f531b4
--- /dev/null
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <composer-vts/2.1/ComposerVts.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace vts {
+
+Composer::Composer() {
+ mComposer = ::testing::VtsHalHidlTargetTestBase::getService<IComposer>();
+ init();
+}
+
+Composer::Composer(const std::string& name) {
+ mComposer = ::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name);
+ init();
+}
+
+void Composer::init() {
+ ASSERT_NE(nullptr, mComposer.get()) << "failed to get composer service";
+
+ std::vector<IComposer::Capability> capabilities = getCapabilities();
+ mCapabilities.insert(capabilities.begin(), capabilities.end());
+}
+
+sp<IComposer> Composer::getRaw() const {
+ return mComposer;
+}
+
+bool Composer::hasCapability(IComposer::Capability capability) const {
+ return mCapabilities.count(capability) > 0;
+}
+
+std::vector<IComposer::Capability> Composer::getCapabilities() {
+ std::vector<IComposer::Capability> capabilities;
+ mComposer->getCapabilities(
+ [&](const auto& tmpCapabilities) { capabilities = tmpCapabilities; });
+
+ return capabilities;
+}
+
+std::string Composer::dumpDebugInfo() {
+ std::string debugInfo;
+ mComposer->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
+
+ return debugInfo;
+}
+
+std::unique_ptr<ComposerClient> Composer::createClient() {
+ std::unique_ptr<ComposerClient> client;
+ mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
+ client = std::make_unique<ComposerClient>(tmpClient);
+ });
+
+ return client;
+}
+
+ComposerClient::ComposerClient(const sp<IComposerClient>& client) : mClient(client) {}
+
+ComposerClient::~ComposerClient() {
+ for (auto it : mDisplayResources) {
+ Display display = it.first;
+ DisplayResource& resource = it.second;
+
+ for (auto layer : resource.layers) {
+ EXPECT_EQ(Error::NONE, mClient->destroyLayer(display, layer))
+ << "failed to destroy layer " << layer;
+ }
+
+ if (resource.isVirtual) {
+ EXPECT_EQ(Error::NONE, mClient->destroyVirtualDisplay(display))
+ << "failed to destroy virtual display " << display;
+ }
+ }
+ mDisplayResources.clear();
+}
+
+sp<IComposerClient> ComposerClient::getRaw() const {
+ return mClient;
+}
+
+void ComposerClient::registerCallback(const sp<IComposerCallback>& callback) {
+ mClient->registerCallback(callback);
+}
+
+uint32_t ComposerClient::getMaxVirtualDisplayCount() {
+ return mClient->getMaxVirtualDisplayCount();
+}
+
+Display ComposerClient::createVirtualDisplay(uint32_t width, uint32_t height,
+ PixelFormat formatHint, uint32_t outputBufferSlotCount,
+ PixelFormat* outFormat) {
+ Display display = 0;
+ mClient->createVirtualDisplay(
+ width, height, formatHint, outputBufferSlotCount,
+ [&](const auto& tmpError, const auto& tmpDisplay, const auto& tmpFormat) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to create virtual display";
+ display = tmpDisplay;
+ *outFormat = tmpFormat;
+
+ ASSERT_TRUE(mDisplayResources.insert({display, DisplayResource(true)}).second)
+ << "duplicated virtual display id " << display;
+ });
+
+ return display;
+}
+
+void ComposerClient::destroyVirtualDisplay(Display display) {
+ Error error = mClient->destroyVirtualDisplay(display);
+ ASSERT_EQ(Error::NONE, error) << "failed to destroy virtual display " << display;
+
+ mDisplayResources.erase(display);
+}
+
+Layer ComposerClient::createLayer(Display display, uint32_t bufferSlotCount) {
+ Layer layer = 0;
+ mClient->createLayer(display, bufferSlotCount, [&](const auto& tmpError, const auto& tmpLayer) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to create layer";
+ layer = tmpLayer;
+
+ auto resourceIt = mDisplayResources.find(display);
+ if (resourceIt == mDisplayResources.end()) {
+ resourceIt = mDisplayResources.insert({display, DisplayResource(false)}).first;
+ }
+
+ ASSERT_TRUE(resourceIt->second.layers.insert(layer).second)
+ << "duplicated layer id " << layer;
+ });
+
+ return layer;
+}
+
+void ComposerClient::destroyLayer(Display display, Layer layer) {
+ Error error = mClient->destroyLayer(display, layer);
+ ASSERT_EQ(Error::NONE, error) << "failed to destroy layer " << layer;
+
+ auto resourceIt = mDisplayResources.find(display);
+ ASSERT_NE(mDisplayResources.end(), resourceIt);
+ resourceIt->second.layers.erase(layer);
+}
+
+Config ComposerClient::getActiveConfig(Display display) {
+ Config config = 0;
+ mClient->getActiveConfig(display, [&](const auto& tmpError, const auto& tmpConfig) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get active config";
+ config = tmpConfig;
+ });
+
+ return config;
+}
+
+bool ComposerClient::getClientTargetSupport(Display display, uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace) {
+ Error error = mClient->getClientTargetSupport(display, width, height, format, dataspace);
+ return error == Error::NONE;
+}
+
+std::vector<ColorMode> ComposerClient::getColorModes(Display display) {
+ std::vector<ColorMode> modes;
+ mClient->getColorModes(display, [&](const auto& tmpError, const auto& tmpMode) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get color mode";
+ modes = tmpMode;
+ });
+
+ return modes;
+}
+
+int32_t ComposerClient::getDisplayAttribute(Display display, Config config,
+ IComposerClient::Attribute attribute) {
+ int32_t value = 0;
+ mClient->getDisplayAttribute(
+ display, config, attribute, [&](const auto& tmpError, const auto& tmpValue) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get display attribute";
+ value = tmpValue;
+ });
+
+ return value;
+}
+
+std::vector<Config> ComposerClient::getDisplayConfigs(Display display) {
+ std::vector<Config> configs;
+ mClient->getDisplayConfigs(display, [&](const auto& tmpError, const auto& tmpConfigs) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get display configs";
+ configs = tmpConfigs;
+ });
+
+ return configs;
+}
+
+std::string ComposerClient::getDisplayName(Display display) {
+ std::string name;
+ mClient->getDisplayName(display, [&](const auto& tmpError, const auto& tmpName) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get display name";
+ name = tmpName.c_str();
+ });
+
+ return name;
+}
+
+IComposerClient::DisplayType ComposerClient::getDisplayType(Display display) {
+ IComposerClient::DisplayType type = IComposerClient::DisplayType::INVALID;
+ mClient->getDisplayType(display, [&](const auto& tmpError, const auto& tmpType) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get display type";
+ type = tmpType;
+ });
+
+ return type;
+}
+
+bool ComposerClient::getDozeSupport(Display display) {
+ bool support = false;
+ mClient->getDozeSupport(display, [&](const auto& tmpError, const auto& tmpSupport) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get doze support";
+ support = tmpSupport;
+ });
+
+ return support;
+}
+
+std::vector<Hdr> ComposerClient::getHdrCapabilities(Display display, float* outMaxLuminance,
+ float* outMaxAverageLuminance,
+ float* outMinLuminance) {
+ std::vector<Hdr> types;
+ mClient->getHdrCapabilities(
+ display, [&](const auto& tmpError, const auto& tmpTypes, const auto& tmpMaxLuminance,
+ const auto& tmpMaxAverageLuminance, const auto& tmpMinLuminance) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get HDR capabilities";
+ types = tmpTypes;
+ *outMaxLuminance = tmpMaxLuminance;
+ *outMaxAverageLuminance = tmpMaxAverageLuminance;
+ *outMinLuminance = tmpMinLuminance;
+ });
+
+ return types;
+}
+
+void ComposerClient::setClientTargetSlotCount(Display display, uint32_t clientTargetSlotCount) {
+ Error error = mClient->setClientTargetSlotCount(display, clientTargetSlotCount);
+ ASSERT_EQ(Error::NONE, error) << "failed to set client target slot count";
+}
+
+void ComposerClient::setActiveConfig(Display display, Config config) {
+ Error error = mClient->setActiveConfig(display, config);
+ ASSERT_EQ(Error::NONE, error) << "failed to set active config";
+}
+
+void ComposerClient::setColorMode(Display display, ColorMode mode) {
+ Error error = mClient->setColorMode(display, mode);
+ ASSERT_EQ(Error::NONE, error) << "failed to set color mode";
+}
+
+void ComposerClient::setPowerMode(Display display, IComposerClient::PowerMode mode) {
+ Error error = mClient->setPowerMode(display, mode);
+ ASSERT_EQ(Error::NONE, error) << "failed to set power mode";
+}
+
+void ComposerClient::setVsyncEnabled(Display display, bool enabled) {
+ IComposerClient::Vsync vsync =
+ (enabled) ? IComposerClient::Vsync::ENABLE : IComposerClient::Vsync::DISABLE;
+ Error error = mClient->setVsyncEnabled(display, vsync);
+ ASSERT_EQ(Error::NONE, error) << "failed to set vsync mode";
+
+ // give the hwbinder thread some time to handle any pending vsync callback
+ if (!enabled) {
+ usleep(5 * 1000);
+ }
+}
+
+void ComposerClient::execute(TestCommandReader* reader, CommandWriterBase* writer) {
+ bool queueChanged = false;
+ uint32_t commandLength = 0;
+ hidl_vec<hidl_handle> commandHandles;
+ ASSERT_TRUE(writer->writeQueue(&queueChanged, &commandLength, &commandHandles));
+
+ if (queueChanged) {
+ auto ret = mClient->setInputCommandQueue(*writer->getMQDescriptor());
+ ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
+ return;
+ }
+
+ mClient->executeCommands(commandLength, commandHandles,
+ [&](const auto& tmpError, const auto& tmpOutQueueChanged,
+ const auto& tmpOutLength, const auto& tmpOutHandles) {
+ ASSERT_EQ(Error::NONE, tmpError);
+
+ if (tmpOutQueueChanged) {
+ mClient->getOutputCommandQueue(
+ [&](const auto& tmpError, const auto& tmpDescriptor) {
+ ASSERT_EQ(Error::NONE, tmpError);
+ reader->setMQDescriptor(tmpDescriptor);
+ });
+ }
+
+ ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles));
+ reader->parse();
+ });
+}
+
+} // namespace vts
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/utils/vts/GraphicsComposerCallback.cpp b/graphics/composer/2.1/utils/vts/GraphicsComposerCallback.cpp
new file mode 100644
index 0000000..1ead138
--- /dev/null
+++ b/graphics/composer/2.1/utils/vts/GraphicsComposerCallback.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <composer-vts/2.1/GraphicsComposerCallback.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace vts {
+
+void GraphicsComposerCallback::setVsyncAllowed(bool allowed) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mVsyncAllowed = allowed;
+}
+
+std::vector<Display> GraphicsComposerCallback::getDisplays() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return std::vector<Display>(mDisplays.begin(), mDisplays.end());
+}
+
+int GraphicsComposerCallback::getInvalidHotplugCount() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mInvalidHotplugCount;
+}
+
+int GraphicsComposerCallback::getInvalidRefreshCount() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mInvalidRefreshCount;
+}
+
+int GraphicsComposerCallback::getInvalidVsyncCount() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mInvalidVsyncCount;
+}
+
+Return<void> GraphicsComposerCallback::onHotplug(Display display, Connection connection) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (connection == Connection::CONNECTED) {
+ if (!mDisplays.insert(display).second) {
+ mInvalidHotplugCount++;
+ }
+ } else if (connection == Connection::DISCONNECTED) {
+ if (!mDisplays.erase(display)) {
+ mInvalidHotplugCount++;
+ }
+ }
+
+ return Void();
+}
+
+Return<void> GraphicsComposerCallback::onRefresh(Display display) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (mDisplays.count(display) == 0) {
+ mInvalidRefreshCount++;
+ }
+
+ return Void();
+}
+
+Return<void> GraphicsComposerCallback::onVsync(Display display, int64_t) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (!mVsyncAllowed || mDisplays.count(display) == 0) {
+ mInvalidVsyncCount++;
+ }
+
+ return Void();
+}
+
+} // namespace vts
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/utils/vts/TestCommandReader.cpp b/graphics/composer/2.1/utils/vts/TestCommandReader.cpp
new file mode 100644
index 0000000..6f8f1ad
--- /dev/null
+++ b/graphics/composer/2.1/utils/vts/TestCommandReader.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <composer-vts/2.1/TestCommandReader.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace vts {
+
+void TestCommandReader::parse() {
+ while (!isEmpty()) {
+ IComposerClient::Command command;
+ uint16_t length;
+ ASSERT_TRUE(beginCommand(&command, &length));
+
+ switch (command) {
+ case IComposerClient::Command::SET_ERROR: {
+ ASSERT_EQ(2, length);
+ auto loc = read();
+ auto err = readSigned();
+ GTEST_FAIL() << "unexpected error " << err << " at location " << loc;
+ } break;
+ case IComposerClient::Command::SELECT_DISPLAY:
+ case IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES:
+ case IComposerClient::Command::SET_DISPLAY_REQUESTS:
+ case IComposerClient::Command::SET_PRESENT_FENCE:
+ case IComposerClient::Command::SET_RELEASE_FENCES:
+ break;
+ default:
+ GTEST_FAIL() << "unexpected return command " << std::hex
+ << static_cast<int>(command);
+ break;
+ }
+
+ endCommand();
+ }
+}
+
+} // namespace vts
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
new file mode 100644
index 0000000..0d883e4
--- /dev/null
+++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include <android/hardware/graphics/composer/2.1/IComposer.h>
+#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
+#include <composer-vts/2.1/TestCommandReader.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace vts {
+
+using android::hardware::graphics::common::V1_0::ColorMode;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::Hdr;
+using android::hardware::graphics::common::V1_0::PixelFormat;
+
+class ComposerClient;
+
+// A wrapper to IComposer.
+class Composer {
+ public:
+ Composer();
+ explicit Composer(const std::string& name);
+
+ sp<IComposer> getRaw() const;
+
+ // Returns true when the composer supports the specified capability.
+ bool hasCapability(IComposer::Capability capability) const;
+
+ std::vector<IComposer::Capability> getCapabilities();
+ std::string dumpDebugInfo();
+ std::unique_ptr<ComposerClient> createClient();
+
+ protected:
+ sp<IComposer> mComposer;
+
+ private:
+ void init();
+
+ std::unordered_set<IComposer::Capability> mCapabilities;
+};
+
+// A wrapper to IComposerClient.
+class ComposerClient {
+ public:
+ ComposerClient(const sp<IComposerClient>& client);
+ ~ComposerClient();
+
+ sp<IComposerClient> getRaw() const;
+
+ void registerCallback(const sp<IComposerCallback>& callback);
+ uint32_t getMaxVirtualDisplayCount();
+
+ Display createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat formatHint,
+ uint32_t outputBufferSlotCount, PixelFormat* outFormat);
+ void destroyVirtualDisplay(Display display);
+
+ Layer createLayer(Display display, uint32_t bufferSlotCount);
+ void destroyLayer(Display display, Layer layer);
+
+ Config getActiveConfig(Display display);
+ bool getClientTargetSupport(Display display, uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace);
+ std::vector<ColorMode> getColorModes(Display display);
+ int32_t getDisplayAttribute(Display display, Config config,
+ IComposerClient::Attribute attribute);
+ std::vector<Config> getDisplayConfigs(Display display);
+ std::string getDisplayName(Display display);
+ IComposerClient::DisplayType getDisplayType(Display display);
+ bool getDozeSupport(Display display);
+ std::vector<Hdr> getHdrCapabilities(Display display, float* outMaxLuminance,
+ float* outMaxAverageLuminance, float* outMinLuminance);
+
+ void setClientTargetSlotCount(Display display, uint32_t clientTargetSlotCount);
+ void setActiveConfig(Display display, Config config);
+ void setColorMode(Display display, ColorMode mode);
+ void setPowerMode(Display display, IComposerClient::PowerMode mode);
+ void setVsyncEnabled(Display display, bool enabled);
+
+ void execute(TestCommandReader* reader, CommandWriterBase* writer);
+
+ private:
+ sp<IComposerClient> mClient;
+
+ // Keep track of all virtual displays and layers. When a test fails with
+ // ASSERT_*, the destructor will clean up the resources for the test.
+ struct DisplayResource {
+ DisplayResource(bool isVirtual_) : isVirtual(isVirtual_) {}
+
+ bool isVirtual;
+ std::unordered_set<Layer> layers;
+ };
+ std::unordered_map<Display, DisplayResource> mDisplayResources;
+};
+
+} // namespace vts
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/GraphicsComposerCallback.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/GraphicsComposerCallback.h
new file mode 100644
index 0000000..e3c348f
--- /dev/null
+++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/GraphicsComposerCallback.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#include <android/hardware/graphics/composer/2.1/IComposerCallback.h>
+
+#include <mutex>
+#include <unordered_set>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace vts {
+
+// IComposerCallback to be installed with IComposerClient::registerCallback.
+class GraphicsComposerCallback : public IComposerCallback {
+ public:
+ void setVsyncAllowed(bool allowed);
+
+ std::vector<Display> getDisplays() const;
+
+ int getInvalidHotplugCount() const;
+
+ int getInvalidRefreshCount() const;
+
+ int getInvalidVsyncCount() const;
+
+ private:
+ Return<void> onHotplug(Display display, Connection connection) override;
+ Return<void> onRefresh(Display display) override;
+ Return<void> onVsync(Display display, int64_t) override;
+
+ mutable std::mutex mMutex;
+ // the set of all currently connected displays
+ std::unordered_set<Display> mDisplays;
+ // true only when vsync is enabled
+ bool mVsyncAllowed = true;
+
+ // track invalid callbacks
+ int mInvalidHotplugCount = 0;
+ int mInvalidRefreshCount = 0;
+ int mInvalidVsyncCount = 0;
+};
+
+} // namespace vts
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/vts/functional/TestCommandReader.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h
similarity index 79%
rename from graphics/composer/2.1/vts/functional/TestCommandReader.h
rename to graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h
index ae25d2d..3888eeb 100644
--- a/graphics/composer/2.1/vts/functional/TestCommandReader.h
+++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef TEST_COMMAND_READER_H
-#define TEST_COMMAND_READER_H
+#pragma once
#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
@@ -24,22 +23,20 @@
namespace graphics {
namespace composer {
namespace V2_1 {
-namespace tests {
+namespace vts {
// A command parser that checks that no error nor unexpected commands are
// returned.
class TestCommandReader : public CommandReaderBase {
- public:
- // Parse all commands in the return command queue. Call GTEST_FAIL() for
- // unexpected errors or commands.
- void parse();
+ public:
+ // Parse all commands in the return command queue. Call GTEST_FAIL() for
+ // unexpected errors or commands.
+ void parse();
};
-} // namespace tests
+} // namespace vts
} // namespace V2_1
} // namespace composer
} // namespace graphics
} // namespace hardware
} // namespace android
-
-#endif // TEST_COMMAND_READER_H
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index 92b65a3..8e346df 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -14,36 +14,6 @@
// limitations under the License.
//
-cc_library_static {
- name: "libVtsHalGraphicsComposerTestUtils",
- defaults: ["hidl_defaults"],
- srcs: [
- "GraphicsComposerCallback.cpp",
- "TestCommandReader.cpp",
- "VtsHalGraphicsComposerTestUtils.cpp",
- ],
- shared_libs: [
- "android.hardware.graphics.composer@2.1",
- "libfmq",
- "libsync",
- ],
- static_libs: [
- "VtsHalHidlTargetTestBase",
- ],
- header_libs: [
- "android.hardware.graphics.composer@2.1-command-buffer",
- ],
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-O0",
- "-g",
- "-DLOG_TAG=\"GraphicsComposerTestUtils\"",
- ],
- export_include_dirs: ["."],
-}
-
cc_test {
name: "VtsHalGraphicsComposerV2_1TargetTest",
defaults: ["VtsHalTargetTestDefaults"],
@@ -57,10 +27,9 @@
static_libs: [
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.0-vts",
- "libVtsHalGraphicsComposerTestUtils",
- "libnativehelper",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/graphics/composer/2.1/vts/functional/GraphicsComposerCallback.cpp b/graphics/composer/2.1/vts/functional/GraphicsComposerCallback.cpp
deleted file mode 100644
index 0ad440c..0000000
--- a/graphics/composer/2.1/vts/functional/GraphicsComposerCallback.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#include "GraphicsComposerCallback.h"
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_1 {
-namespace tests {
-
-void GraphicsComposerCallback::setVsyncAllowed(bool allowed) {
- std::lock_guard<std::mutex> lock(mMutex);
- mVsyncAllowed = allowed;
-}
-
-std::vector<Display> GraphicsComposerCallback::getDisplays() const {
- std::lock_guard<std::mutex> lock(mMutex);
- return std::vector<Display>(mDisplays.begin(), mDisplays.end());
-}
-
-int GraphicsComposerCallback::getInvalidHotplugCount() const {
- std::lock_guard<std::mutex> lock(mMutex);
- return mInvalidHotplugCount;
-}
-
-int GraphicsComposerCallback::getInvalidRefreshCount() const {
- std::lock_guard<std::mutex> lock(mMutex);
- return mInvalidRefreshCount;
-}
-
-int GraphicsComposerCallback::getInvalidVsyncCount() const {
- std::lock_guard<std::mutex> lock(mMutex);
- return mInvalidVsyncCount;
-}
-
-Return<void> GraphicsComposerCallback::onHotplug(Display display,
- Connection connection) {
- std::lock_guard<std::mutex> lock(mMutex);
-
- if (connection == Connection::CONNECTED) {
- if (!mDisplays.insert(display).second) {
- mInvalidHotplugCount++;
- }
- } else if (connection == Connection::DISCONNECTED) {
- if (!mDisplays.erase(display)) {
- mInvalidHotplugCount++;
- }
- }
-
- return Void();
-}
-
-Return<void> GraphicsComposerCallback::onRefresh(Display display) {
- std::lock_guard<std::mutex> lock(mMutex);
-
- if (mDisplays.count(display) == 0) {
- mInvalidRefreshCount++;
- }
-
- return Void();
-}
-
-Return<void> GraphicsComposerCallback::onVsync(Display display, int64_t) {
- std::lock_guard<std::mutex> lock(mMutex);
-
- if (!mVsyncAllowed || mDisplays.count(display) == 0) {
- mInvalidVsyncCount++;
- }
-
- return Void();
-}
-
-} // namespace tests
-} // namespace V2_1
-} // namespace composer
-} // namespace graphics
-} // namespace hardware
-} // namespace android
diff --git a/graphics/composer/2.1/vts/functional/GraphicsComposerCallback.h b/graphics/composer/2.1/vts/functional/GraphicsComposerCallback.h
deleted file mode 100644
index e332086..0000000
--- a/graphics/composer/2.1/vts/functional/GraphicsComposerCallback.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef GRAPHICS_COMPOSER_CALLBACK_H
-#define GRAPHICS_COMPOSER_CALLBACK_H
-
-#include <android/hardware/graphics/composer/2.1/IComposerCallback.h>
-
-#include <mutex>
-#include <unordered_set>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_1 {
-namespace tests {
-
-// IComposerCallback to be installed with IComposerClient::registerCallback.
-class GraphicsComposerCallback : public IComposerCallback {
- public:
- void setVsyncAllowed(bool allowed);
-
- std::vector<Display> getDisplays() const;
-
- int getInvalidHotplugCount() const;
-
- int getInvalidRefreshCount() const;
-
- int getInvalidVsyncCount() const;
-
- private:
- Return<void> onHotplug(Display display, Connection connection) override;
- Return<void> onRefresh(Display display) override;
- Return<void> onVsync(Display display, int64_t) override;
-
- mutable std::mutex mMutex;
- // the set of all currently connected displays
- std::unordered_set<Display> mDisplays;
- // true only when vsync is enabled
- bool mVsyncAllowed = true;
-
- // track invalid callbacks
- int mInvalidHotplugCount = 0;
- int mInvalidRefreshCount = 0;
- int mInvalidVsyncCount = 0;
-};
-
-} // namespace tests
-} // namespace V2_1
-} // namespace composer
-} // namespace graphics
-} // namespace hardware
-} // namespace android
-
-#endif // GRAPHICS_COMPOSER_CALLBACK_H
diff --git a/graphics/composer/2.1/vts/functional/TestCommandReader.cpp b/graphics/composer/2.1/vts/functional/TestCommandReader.cpp
deleted file mode 100644
index b1f9aca..0000000
--- a/graphics/composer/2.1/vts/functional/TestCommandReader.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#include "TestCommandReader.h"
-
-#include <gtest/gtest.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_1 {
-namespace tests {
-
-void TestCommandReader::parse() {
- while (!isEmpty()) {
- IComposerClient::Command command;
- uint16_t length;
- ASSERT_TRUE(beginCommand(&command, &length));
-
- switch (command) {
- case IComposerClient::Command::SET_ERROR: {
- ASSERT_EQ(2, length);
- auto loc = read();
- auto err = readSigned();
- GTEST_FAIL() << "unexpected error " << err << " at location " << loc;
- } break;
- case IComposerClient::Command::SELECT_DISPLAY:
- case IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES:
- case IComposerClient::Command::SET_DISPLAY_REQUESTS:
- case IComposerClient::Command::SET_PRESENT_FENCE:
- case IComposerClient::Command::SET_RELEASE_FENCES:
- break;
- default:
- GTEST_FAIL() << "unexpected return command " << std::hex
- << static_cast<int>(command);
- break;
- }
-
- endCommand();
- }
-}
-
-} // namespace tests
-} // namespace V2_1
-} // namespace composer
-} // namespace graphics
-} // namespace hardware
-} // namespace android
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.cpp
deleted file mode 100644
index c66cdd0..0000000
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.cpp
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#include <VtsHalHidlTargetTestBase.h>
-
-#include "VtsHalGraphicsComposerTestUtils.h"
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_1 {
-namespace tests {
-
-Composer::Composer() {
- mComposer = ::testing::VtsHalHidlTargetTestBase::getService<IComposer>();
- init();
-}
-
-Composer::Composer(const std::string& name) {
- mComposer = ::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name);
- init();
-}
-
-void Composer::init() {
- ASSERT_NE(nullptr, mComposer.get()) << "failed to get composer service";
-
- std::vector<IComposer::Capability> capabilities = getCapabilities();
- mCapabilities.insert(capabilities.begin(), capabilities.end());
-}
-
-sp<IComposer> Composer::getRaw() const { return mComposer; }
-
-bool Composer::hasCapability(IComposer::Capability capability) const {
- return mCapabilities.count(capability) > 0;
-}
-
-std::vector<IComposer::Capability> Composer::getCapabilities() {
- std::vector<IComposer::Capability> capabilities;
- mComposer->getCapabilities(
- [&](const auto& tmpCapabilities) { capabilities = tmpCapabilities; });
-
- return capabilities;
-}
-
-std::string Composer::dumpDebugInfo() {
- std::string debugInfo;
- mComposer->dumpDebugInfo(
- [&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
-
- return debugInfo;
-}
-
-std::unique_ptr<ComposerClient> Composer::createClient() {
- std::unique_ptr<ComposerClient> client;
- mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) {
- ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
- client = std::make_unique<ComposerClient>(tmpClient);
- });
-
- return client;
-}
-
-ComposerClient::ComposerClient(const sp<IComposerClient>& client)
- : mClient(client) {}
-
-ComposerClient::~ComposerClient() {
- for (auto it : mDisplayResources) {
- Display display = it.first;
- DisplayResource& resource = it.second;
-
- for (auto layer : resource.layers) {
- EXPECT_EQ(Error::NONE, mClient->destroyLayer(display, layer))
- << "failed to destroy layer " << layer;
- }
-
- if (resource.isVirtual) {
- EXPECT_EQ(Error::NONE, mClient->destroyVirtualDisplay(display))
- << "failed to destroy virtual display " << display;
- }
- }
- mDisplayResources.clear();
-}
-
-sp<IComposerClient> ComposerClient::getRaw() const { return mClient; }
-
-void ComposerClient::registerCallback(const sp<IComposerCallback>& callback) {
- mClient->registerCallback(callback);
-}
-
-uint32_t ComposerClient::getMaxVirtualDisplayCount() {
- return mClient->getMaxVirtualDisplayCount();
-}
-
-Display ComposerClient::createVirtualDisplay(uint32_t width, uint32_t height,
- PixelFormat formatHint,
- uint32_t outputBufferSlotCount,
- PixelFormat* outFormat) {
- Display display = 0;
- mClient->createVirtualDisplay(
- width, height, formatHint, outputBufferSlotCount,
- [&](const auto& tmpError, const auto& tmpDisplay, const auto& tmpFormat) {
- ASSERT_EQ(Error::NONE, tmpError) << "failed to create virtual display";
- display = tmpDisplay;
- *outFormat = tmpFormat;
-
- ASSERT_TRUE(
- mDisplayResources.insert({display, DisplayResource(true)}).second)
- << "duplicated virtual display id " << display;
- });
-
- return display;
-}
-
-void ComposerClient::destroyVirtualDisplay(Display display) {
- Error error = mClient->destroyVirtualDisplay(display);
- ASSERT_EQ(Error::NONE, error)
- << "failed to destroy virtual display " << display;
-
- mDisplayResources.erase(display);
-}
-
-Layer ComposerClient::createLayer(Display display, uint32_t bufferSlotCount) {
- Layer layer = 0;
- mClient->createLayer(
- display, bufferSlotCount,
- [&](const auto& tmpError, const auto& tmpLayer) {
- ASSERT_EQ(Error::NONE, tmpError) << "failed to create layer";
- layer = tmpLayer;
-
- auto resourceIt = mDisplayResources.find(display);
- if (resourceIt == mDisplayResources.end()) {
- resourceIt =
- mDisplayResources.insert({display, DisplayResource(false)}).first;
- }
-
- ASSERT_TRUE(resourceIt->second.layers.insert(layer).second)
- << "duplicated layer id " << layer;
- });
-
- return layer;
-}
-
-void ComposerClient::destroyLayer(Display display, Layer layer) {
- Error error = mClient->destroyLayer(display, layer);
- ASSERT_EQ(Error::NONE, error) << "failed to destroy layer " << layer;
-
- auto resourceIt = mDisplayResources.find(display);
- ASSERT_NE(mDisplayResources.end(), resourceIt);
- resourceIt->second.layers.erase(layer);
-}
-
-Config ComposerClient::getActiveConfig(Display display) {
- Config config = 0;
- mClient->getActiveConfig(
- display, [&](const auto& tmpError, const auto& tmpConfig) {
- ASSERT_EQ(Error::NONE, tmpError) << "failed to get active config";
- config = tmpConfig;
- });
-
- return config;
-}
-
-bool ComposerClient::getClientTargetSupport(Display display, uint32_t width,
- uint32_t height, PixelFormat format,
- Dataspace dataspace) {
- Error error = mClient->getClientTargetSupport(display, width, height, format,
- dataspace);
- return error == Error::NONE;
-}
-
-std::vector<ColorMode> ComposerClient::getColorModes(Display display) {
- std::vector<ColorMode> modes;
- mClient->getColorModes(
- display, [&](const auto& tmpError, const auto& tmpMode) {
- ASSERT_EQ(Error::NONE, tmpError) << "failed to get color mode";
- modes = tmpMode;
- });
-
- return modes;
-}
-
-int32_t ComposerClient::getDisplayAttribute(
- Display display, Config config, IComposerClient::Attribute attribute) {
- int32_t value = 0;
- mClient->getDisplayAttribute(display, config, attribute,
- [&](const auto& tmpError, const auto& tmpValue) {
- ASSERT_EQ(Error::NONE, tmpError)
- << "failed to get display attribute";
- value = tmpValue;
- });
-
- return value;
-}
-
-std::vector<Config> ComposerClient::getDisplayConfigs(Display display) {
- std::vector<Config> configs;
- mClient->getDisplayConfigs(
- display, [&](const auto& tmpError, const auto& tmpConfigs) {
- ASSERT_EQ(Error::NONE, tmpError) << "failed to get display configs";
- configs = tmpConfigs;
- });
-
- return configs;
-}
-
-std::string ComposerClient::getDisplayName(Display display) {
- std::string name;
- mClient->getDisplayName(
- display, [&](const auto& tmpError, const auto& tmpName) {
- ASSERT_EQ(Error::NONE, tmpError) << "failed to get display name";
- name = tmpName.c_str();
- });
-
- return name;
-}
-
-IComposerClient::DisplayType ComposerClient::getDisplayType(Display display) {
- IComposerClient::DisplayType type = IComposerClient::DisplayType::INVALID;
- mClient->getDisplayType(
- display, [&](const auto& tmpError, const auto& tmpType) {
- ASSERT_EQ(Error::NONE, tmpError) << "failed to get display type";
- type = tmpType;
- });
-
- return type;
-}
-
-bool ComposerClient::getDozeSupport(Display display) {
- bool support = false;
- mClient->getDozeSupport(
- display, [&](const auto& tmpError, const auto& tmpSupport) {
- ASSERT_EQ(Error::NONE, tmpError) << "failed to get doze support";
- support = tmpSupport;
- });
-
- return support;
-}
-
-std::vector<Hdr> ComposerClient::getHdrCapabilities(
- Display display, float* outMaxLuminance, float* outMaxAverageLuminance,
- float* outMinLuminance) {
- std::vector<Hdr> types;
- mClient->getHdrCapabilities(
- display,
- [&](const auto& tmpError, const auto& tmpTypes,
- const auto& tmpMaxLuminance, const auto& tmpMaxAverageLuminance,
- const auto& tmpMinLuminance) {
- ASSERT_EQ(Error::NONE, tmpError) << "failed to get HDR capabilities";
- types = tmpTypes;
- *outMaxLuminance = tmpMaxLuminance;
- *outMaxAverageLuminance = tmpMaxAverageLuminance;
- *outMinLuminance = tmpMinLuminance;
- });
-
- return types;
-}
-
-void ComposerClient::setClientTargetSlotCount(Display display,
- uint32_t clientTargetSlotCount) {
- Error error =
- mClient->setClientTargetSlotCount(display, clientTargetSlotCount);
- ASSERT_EQ(Error::NONE, error) << "failed to set client target slot count";
-}
-
-void ComposerClient::setActiveConfig(Display display, Config config) {
- Error error = mClient->setActiveConfig(display, config);
- ASSERT_EQ(Error::NONE, error) << "failed to set active config";
-}
-
-void ComposerClient::setColorMode(Display display, ColorMode mode) {
- Error error = mClient->setColorMode(display, mode);
- ASSERT_EQ(Error::NONE, error) << "failed to set color mode";
-}
-
-void ComposerClient::setPowerMode(Display display,
- IComposerClient::PowerMode mode) {
- Error error = mClient->setPowerMode(display, mode);
- ASSERT_EQ(Error::NONE, error) << "failed to set power mode";
-}
-
-void ComposerClient::setVsyncEnabled(Display display, bool enabled) {
- IComposerClient::Vsync vsync = (enabled) ? IComposerClient::Vsync::ENABLE
- : IComposerClient::Vsync::DISABLE;
- Error error = mClient->setVsyncEnabled(display, vsync);
- ASSERT_EQ(Error::NONE, error) << "failed to set vsync mode";
-
- // give the hwbinder thread some time to handle any pending vsync callback
- if (!enabled) {
- usleep(5 * 1000);
- }
-}
-
-void ComposerClient::execute(TestCommandReader* reader,
- CommandWriterBase* writer) {
- bool queueChanged = false;
- uint32_t commandLength = 0;
- hidl_vec<hidl_handle> commandHandles;
- ASSERT_TRUE(
- writer->writeQueue(&queueChanged, &commandLength, &commandHandles));
-
- if (queueChanged) {
- auto ret = mClient->setInputCommandQueue(*writer->getMQDescriptor());
- ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
- return;
- }
-
- mClient->executeCommands(
- commandLength, commandHandles,
- [&](const auto& tmpError, const auto& tmpOutQueueChanged,
- const auto& tmpOutLength, const auto& tmpOutHandles) {
- ASSERT_EQ(Error::NONE, tmpError);
-
- if (tmpOutQueueChanged) {
- mClient->getOutputCommandQueue(
- [&](const auto& tmpError, const auto& tmpDescriptor) {
- ASSERT_EQ(Error::NONE, tmpError);
- reader->setMQDescriptor(tmpDescriptor);
- });
- }
-
- ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles));
- reader->parse();
- });
-}
-
-} // namespace tests
-} // namespace V2_1
-} // namespace composer
-} // namespace graphics
-} // namespace hardware
-} // namespace android
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h
deleted file mode 100644
index 00d9d8c..0000000
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef VTS_HAL_GRAPHICS_COMPOSER_UTILS
-#define VTS_HAL_GRAPHICS_COMPOSER_UTILS
-
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-#include <android/hardware/graphics/composer/2.1/IComposer.h>
-#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
-#include <utils/StrongPointer.h>
-
-#include "TestCommandReader.h"
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_1 {
-namespace tests {
-
-using android::hardware::graphics::common::V1_0::ColorMode;
-using android::hardware::graphics::common::V1_0::Dataspace;
-using android::hardware::graphics::common::V1_0::Hdr;
-using android::hardware::graphics::common::V1_0::PixelFormat;
-
-class ComposerClient;
-
-// A wrapper to IComposer.
-class Composer {
- public:
- Composer();
- explicit Composer(const std::string& name);
-
- sp<IComposer> getRaw() const;
-
- // Returns true when the composer supports the specified capability.
- bool hasCapability(IComposer::Capability capability) const;
-
- std::vector<IComposer::Capability> getCapabilities();
- std::string dumpDebugInfo();
- std::unique_ptr<ComposerClient> createClient();
-
- protected:
- sp<IComposer> mComposer;
-
- private:
- void init();
-
- std::unordered_set<IComposer::Capability> mCapabilities;
-};
-
-// A wrapper to IComposerClient.
-class ComposerClient {
- public:
- ComposerClient(const sp<IComposerClient>& client);
- ~ComposerClient();
-
- sp<IComposerClient> getRaw() const;
-
- void registerCallback(const sp<IComposerCallback>& callback);
- uint32_t getMaxVirtualDisplayCount();
-
- Display createVirtualDisplay(uint32_t width, uint32_t height,
- PixelFormat formatHint,
- uint32_t outputBufferSlotCount,
- PixelFormat* outFormat);
- void destroyVirtualDisplay(Display display);
-
- Layer createLayer(Display display, uint32_t bufferSlotCount);
- void destroyLayer(Display display, Layer layer);
-
- Config getActiveConfig(Display display);
- bool getClientTargetSupport(Display display, uint32_t width, uint32_t height,
- PixelFormat format, Dataspace dataspace);
- std::vector<ColorMode> getColorModes(Display display);
- int32_t getDisplayAttribute(Display display, Config config,
- IComposerClient::Attribute attribute);
- std::vector<Config> getDisplayConfigs(Display display);
- std::string getDisplayName(Display display);
- IComposerClient::DisplayType getDisplayType(Display display);
- bool getDozeSupport(Display display);
- std::vector<Hdr> getHdrCapabilities(Display display, float* outMaxLuminance,
- float* outMaxAverageLuminance,
- float* outMinLuminance);
-
- void setClientTargetSlotCount(Display display,
- uint32_t clientTargetSlotCount);
- void setActiveConfig(Display display, Config config);
- void setColorMode(Display display, ColorMode mode);
- void setPowerMode(Display display, IComposerClient::PowerMode mode);
- void setVsyncEnabled(Display display, bool enabled);
-
- void execute(TestCommandReader* reader, CommandWriterBase* writer);
-
- private:
- sp<IComposerClient> mClient;
-
- // Keep track of all virtual displays and layers. When a test fails with
- // ASSERT_*, the destructor will clean up the resources for the test.
- struct DisplayResource {
- DisplayResource(bool isVirtual_) : isVirtual(isVirtual_) {}
-
- bool isVirtual;
- std::unordered_set<Layer> layers;
- };
- std::unordered_map<Display, DisplayResource> mDisplayResources;
-};
-
-} // namespace tests
-} // namespace V2_1
-} // namespace composer
-} // namespace graphics
-} // namespace hardware
-} // namespace android
-
-#endif // VTS_HAL_GRAPHICS_COMPOSER_UTILS
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index 376ee37..8b8b530 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -17,10 +17,10 @@
#define LOG_TAG "graphics_composer_hidl_hal_test"
#include <android-base/logging.h>
+#include <composer-vts/2.1/ComposerVts.h>
+#include <composer-vts/2.1/GraphicsComposerCallback.h>
+#include <composer-vts/2.1/TestCommandReader.h>
#include <mapper-vts/2.0/MapperVts.h>
-#include "GraphicsComposerCallback.h"
-#include "TestCommandReader.h"
-#include "VtsHalGraphicsComposerTestUtils.h"
#include <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>
@@ -38,7 +38,7 @@
namespace graphics {
namespace composer {
namespace V2_1 {
-namespace tests {
+namespace vts {
namespace {
using android::hardware::graphics::common::V1_0::BufferUsage;
@@ -69,53 +69,53 @@
};
class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- protected:
- void SetUp() override {
- ASSERT_NO_FATAL_FAILURE(
- mComposer = std::make_unique<Composer>(
- GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
- ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
+ protected:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(
+ mComposer = std::make_unique<Composer>(
+ GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+ ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
- mComposerCallback = new GraphicsComposerCallback;
- mComposerClient->registerCallback(mComposerCallback);
+ mComposerCallback = new GraphicsComposerCallback;
+ mComposerClient->registerCallback(mComposerCallback);
- // assume the first display is primary and is never removed
- mPrimaryDisplay = waitForFirstDisplay();
+ // assume the first display is primary and is never removed
+ mPrimaryDisplay = waitForFirstDisplay();
- // explicitly disable vsync
- mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
- mComposerCallback->setVsyncAllowed(false);
- }
-
- void TearDown() override {
- if (mComposerCallback != nullptr) {
- EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
- EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
- EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
+ // explicitly disable vsync
+ mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
+ mComposerCallback->setVsyncAllowed(false);
}
- }
- // use the slot count usually set by SF
- static constexpr uint32_t kBufferSlotCount = 64;
-
- std::unique_ptr<Composer> mComposer;
- std::unique_ptr<ComposerClient> mComposerClient;
- sp<GraphicsComposerCallback> mComposerCallback;
- // the first display and is assumed never to be removed
- Display mPrimaryDisplay;
-
- private:
- Display waitForFirstDisplay() {
- while (true) {
- std::vector<Display> displays = mComposerCallback->getDisplays();
- if (displays.empty()) {
- usleep(5 * 1000);
- continue;
- }
-
- return displays[0];
+ void TearDown() override {
+ if (mComposerCallback != nullptr) {
+ EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
+ EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
+ EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
+ }
}
- }
+
+ // use the slot count usually set by SF
+ static constexpr uint32_t kBufferSlotCount = 64;
+
+ std::unique_ptr<Composer> mComposer;
+ std::unique_ptr<ComposerClient> mComposerClient;
+ sp<GraphicsComposerCallback> mComposerCallback;
+ // the first display and is assumed never to be removed
+ Display mPrimaryDisplay;
+
+ private:
+ Display waitForFirstDisplay() {
+ while (true) {
+ std::vector<Display> displays = mComposerCallback->getDisplays();
+ if (displays.empty()) {
+ usleep(5 * 1000);
+ continue;
+ }
+
+ return displays[0];
+ }
+ }
};
/**
@@ -124,16 +124,17 @@
* Test that IComposer::getCapabilities returns no invalid capabilities.
*/
TEST_F(GraphicsComposerHidlTest, GetCapabilities) {
- auto capabilities = mComposer->getCapabilities();
- ASSERT_EQ(capabilities.end(),
- std::find(capabilities.begin(), capabilities.end(),
- IComposer::Capability::INVALID));
+ auto capabilities = mComposer->getCapabilities();
+ ASSERT_EQ(capabilities.end(),
+ std::find(capabilities.begin(), capabilities.end(), IComposer::Capability::INVALID));
}
/**
* Test IComposer::dumpDebugInfo.
*/
-TEST_F(GraphicsComposerHidlTest, DumpDebugInfo) { mComposer->dumpDebugInfo(); }
+TEST_F(GraphicsComposerHidlTest, DumpDebugInfo) {
+ mComposer->dumpDebugInfo();
+}
/**
* Test IComposer::createClient.
@@ -141,9 +142,8 @@
* Test that IComposerClient is a singleton.
*/
TEST_F(GraphicsComposerHidlTest, CreateClientSingleton) {
- mComposer->getRaw()->createClient([&](const auto& tmpError, const auto&) {
- EXPECT_EQ(Error::NO_RESOURCES, tmpError);
- });
+ mComposer->getRaw()->createClient(
+ [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::NO_RESOURCES, tmpError); });
}
/**
@@ -153,22 +153,22 @@
* Test that virtual displays can be created and has the correct display type.
*/
TEST_F(GraphicsComposerHidlTest, CreateVirtualDisplay) {
- if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
- GTEST_SUCCEED() << "no virtual display support";
- return;
- }
+ if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
+ GTEST_SUCCEED() << "no virtual display support";
+ return;
+ }
- Display display;
- PixelFormat format;
- ASSERT_NO_FATAL_FAILURE(display = mComposerClient->createVirtualDisplay(
- 64, 64, PixelFormat::IMPLEMENTATION_DEFINED,
- kBufferSlotCount, &format));
+ Display display;
+ PixelFormat format;
+ ASSERT_NO_FATAL_FAILURE(
+ display = mComposerClient->createVirtualDisplay(64, 64, PixelFormat::IMPLEMENTATION_DEFINED,
+ kBufferSlotCount, &format));
- // test display type
- IComposerClient::DisplayType type = mComposerClient->getDisplayType(display);
- EXPECT_EQ(IComposerClient::DisplayType::VIRTUAL, type);
+ // test display type
+ IComposerClient::DisplayType type = mComposerClient->getDisplayType(display);
+ EXPECT_EQ(IComposerClient::DisplayType::VIRTUAL, type);
- mComposerClient->destroyVirtualDisplay(display);
+ mComposerClient->destroyVirtualDisplay(display);
}
/**
@@ -177,18 +177,18 @@
* Test that layers can be created and destroyed.
*/
TEST_F(GraphicsComposerHidlTest, CreateLayer) {
- Layer layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(layer =
+ mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
- mComposerClient->destroyLayer(mPrimaryDisplay, layer);
+ mComposerClient->destroyLayer(mPrimaryDisplay, layer);
}
/**
* Test IComposerClient::getDisplayName.
*/
TEST_F(GraphicsComposerHidlTest, GetDisplayName) {
- mComposerClient->getDisplayName(mPrimaryDisplay);
+ mComposerClient->getDisplayName(mPrimaryDisplay);
}
/**
@@ -198,8 +198,8 @@
* for the primary display.
*/
TEST_F(GraphicsComposerHidlTest, GetDisplayType) {
- ASSERT_EQ(IComposerClient::DisplayType::PHYSICAL,
- mComposerClient->getDisplayType(mPrimaryDisplay));
+ ASSERT_EQ(IComposerClient::DisplayType::PHYSICAL,
+ mComposerClient->getDisplayType(mPrimaryDisplay));
}
/**
@@ -209,22 +209,20 @@
* required client targets.
*/
TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport) {
- std::vector<Config> configs =
- mComposerClient->getDisplayConfigs(mPrimaryDisplay);
- for (auto config : configs) {
- int32_t width = mComposerClient->getDisplayAttribute(
- mPrimaryDisplay, config, IComposerClient::Attribute::WIDTH);
- int32_t height = mComposerClient->getDisplayAttribute(
- mPrimaryDisplay, config, IComposerClient::Attribute::HEIGHT);
- ASSERT_LT(0, width);
- ASSERT_LT(0, height);
+ std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
+ for (auto config : configs) {
+ int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
+ IComposerClient::Attribute::WIDTH);
+ int32_t height = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
+ IComposerClient::Attribute::HEIGHT);
+ ASSERT_LT(0, width);
+ ASSERT_LT(0, height);
- mComposerClient->setActiveConfig(mPrimaryDisplay, config);
+ mComposerClient->setActiveConfig(mPrimaryDisplay, config);
- ASSERT_TRUE(mComposerClient->getClientTargetSupport(
- mPrimaryDisplay, width, height, PixelFormat::RGBA_8888,
- Dataspace::UNKNOWN));
- }
+ ASSERT_TRUE(mComposerClient->getClientTargetSupport(
+ mPrimaryDisplay, width, height, PixelFormat::RGBA_8888, Dataspace::UNKNOWN));
+ }
}
/**
@@ -234,47 +232,44 @@
* formats, and succeeds or fails correctly for optional attributes.
*/
TEST_F(GraphicsComposerHidlTest, GetDisplayAttribute) {
- std::vector<Config> configs =
- mComposerClient->getDisplayConfigs(mPrimaryDisplay);
- for (auto config : configs) {
- const std::array<IComposerClient::Attribute, 3> requiredAttributes = {{
- IComposerClient::Attribute::WIDTH, IComposerClient::Attribute::HEIGHT,
- IComposerClient::Attribute::VSYNC_PERIOD,
- }};
- for (auto attribute : requiredAttributes) {
- mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, attribute);
- }
+ std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
+ for (auto config : configs) {
+ const std::array<IComposerClient::Attribute, 3> requiredAttributes = {{
+ IComposerClient::Attribute::WIDTH, IComposerClient::Attribute::HEIGHT,
+ IComposerClient::Attribute::VSYNC_PERIOD,
+ }};
+ for (auto attribute : requiredAttributes) {
+ mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, attribute);
+ }
- const std::array<IComposerClient::Attribute, 2> optionalAttributes = {{
- IComposerClient::Attribute::DPI_X, IComposerClient::Attribute::DPI_Y,
- }};
- for (auto attribute : optionalAttributes) {
- mComposerClient->getRaw()->getDisplayAttribute(
- mPrimaryDisplay, config, attribute,
- [&](const auto& tmpError, const auto&) {
- EXPECT_TRUE(tmpError == Error::NONE ||
- tmpError == Error::UNSUPPORTED);
- });
+ const std::array<IComposerClient::Attribute, 2> optionalAttributes = {{
+ IComposerClient::Attribute::DPI_X, IComposerClient::Attribute::DPI_Y,
+ }};
+ for (auto attribute : optionalAttributes) {
+ mComposerClient->getRaw()->getDisplayAttribute(
+ mPrimaryDisplay, config, attribute, [&](const auto& tmpError, const auto&) {
+ EXPECT_TRUE(tmpError == Error::NONE || tmpError == Error::UNSUPPORTED);
+ });
+ }
}
- }
}
/**
* Test IComposerClient::getHdrCapabilities.
*/
TEST_F(GraphicsComposerHidlTest, GetHdrCapabilities) {
- float maxLuminance;
- float maxAverageLuminance;
- float minLuminance;
- mComposerClient->getHdrCapabilities(mPrimaryDisplay, &maxLuminance,
- &maxAverageLuminance, &minLuminance);
+ float maxLuminance;
+ float maxAverageLuminance;
+ float minLuminance;
+ mComposerClient->getHdrCapabilities(mPrimaryDisplay, &maxLuminance, &maxAverageLuminance,
+ &minLuminance);
}
/**
* Test IComposerClient::setClientTargetSlotCount.
*/
TEST_F(GraphicsComposerHidlTest, SetClientTargetSlotCount) {
- mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount);
+ mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount);
}
/**
@@ -284,12 +279,11 @@
* configs.
*/
TEST_F(GraphicsComposerHidlTest, SetActiveConfig) {
- std::vector<Config> configs =
- mComposerClient->getDisplayConfigs(mPrimaryDisplay);
- for (auto config : configs) {
- mComposerClient->setActiveConfig(mPrimaryDisplay, config);
- ASSERT_EQ(config, mComposerClient->getActiveConfig(mPrimaryDisplay));
- }
+ std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
+ for (auto config : configs) {
+ mComposerClient->setActiveConfig(mPrimaryDisplay, config);
+ ASSERT_EQ(config, mComposerClient->getActiveConfig(mPrimaryDisplay));
+ }
}
/**
@@ -298,11 +292,10 @@
* Test that IComposerClient::setColorMode succeeds for all color modes.
*/
TEST_F(GraphicsComposerHidlTest, SetColorMode) {
- std::vector<ColorMode> modes =
- mComposerClient->getColorModes(mPrimaryDisplay);
- for (auto mode : modes) {
- mComposerClient->setColorMode(mPrimaryDisplay, mode);
- }
+ std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
+ for (auto mode : modes) {
+ mComposerClient->setColorMode(mPrimaryDisplay, mode);
+ }
}
/**
@@ -311,20 +304,20 @@
* Test that IComposerClient::setPowerMode succeeds for all power modes.
*/
TEST_F(GraphicsComposerHidlTest, SetPowerMode) {
- std::vector<IComposerClient::PowerMode> modes;
- modes.push_back(IComposerClient::PowerMode::OFF);
+ std::vector<IComposerClient::PowerMode> modes;
+ modes.push_back(IComposerClient::PowerMode::OFF);
- if (mComposerClient->getDozeSupport(mPrimaryDisplay)) {
- modes.push_back(IComposerClient::PowerMode::DOZE);
- modes.push_back(IComposerClient::PowerMode::DOZE_SUSPEND);
- }
+ if (mComposerClient->getDozeSupport(mPrimaryDisplay)) {
+ modes.push_back(IComposerClient::PowerMode::DOZE);
+ modes.push_back(IComposerClient::PowerMode::DOZE_SUSPEND);
+ }
- // push ON last
- modes.push_back(IComposerClient::PowerMode::ON);
+ // push ON last
+ modes.push_back(IComposerClient::PowerMode::ON);
- for (auto mode : modes) {
- mComposerClient->setPowerMode(mPrimaryDisplay, mode);
- }
+ for (auto mode : modes) {
+ mComposerClient->setPowerMode(mPrimaryDisplay, mode);
+ }
}
/**
@@ -334,369 +327,365 @@
* spurious vsync events.
*/
TEST_F(GraphicsComposerHidlTest, SetVsyncEnabled) {
- mComposerCallback->setVsyncAllowed(true);
+ mComposerCallback->setVsyncAllowed(true);
- mComposerClient->setVsyncEnabled(mPrimaryDisplay, true);
- usleep(60 * 1000);
- mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
+ mComposerClient->setVsyncEnabled(mPrimaryDisplay, true);
+ usleep(60 * 1000);
+ mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
- mComposerCallback->setVsyncAllowed(false);
+ mComposerCallback->setVsyncAllowed(false);
}
// Tests for IComposerClient::Command.
class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest {
- protected:
- void SetUp() override {
- ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());
+ protected:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());
- ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
+ ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
- mWriter = std::make_unique<CommandWriterBase>(1024);
- mReader = std::make_unique<TestCommandReader>();
- }
+ mWriter = std::make_unique<CommandWriterBase>(1024);
+ mReader = std::make_unique<TestCommandReader>();
+ }
- void TearDown() override {
- ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
- }
+ void TearDown() override { ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown()); }
- const native_handle_t* allocate() {
- IMapper::BufferDescriptorInfo info{};
- info.width = 64;
- info.height = 64;
- info.layerCount = 1;
- info.format = PixelFormat::RGBA_8888;
- info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::CPU_READ_OFTEN);
+ const native_handle_t* allocate() {
+ IMapper::BufferDescriptorInfo info{};
+ info.width = 64;
+ info.height = 64;
+ info.layerCount = 1;
+ info.format = PixelFormat::RGBA_8888;
+ info.usage =
+ static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
- return mGralloc->allocate(info);
- }
+ return mGralloc->allocate(info);
+ }
- void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
+ void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
- std::unique_ptr<CommandWriterBase> mWriter;
- std::unique_ptr<TestCommandReader> mReader;
+ std::unique_ptr<CommandWriterBase> mWriter;
+ std::unique_ptr<TestCommandReader> mReader;
- private:
- std::unique_ptr<Gralloc> mGralloc;
+ private:
+ std::unique_ptr<Gralloc> mGralloc;
};
/**
* Test IComposerClient::Command::SET_COLOR_TRANSFORM.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_COLOR_TRANSFORM) {
- const std::array<float, 16> identity = {{
- 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 1.0f,
- }};
+ const std::array<float, 16> identity = {{
+ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 1.0f,
+ }};
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->setColorTransform(identity.data(), ColorTransform::IDENTITY);
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->setColorTransform(identity.data(), ColorTransform::IDENTITY);
- execute();
+ execute();
}
/**
* Test IComposerClient::Command::SET_CLIENT_TARGET.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_CLIENT_TARGET) {
- mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount);
+ mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount);
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->setClientTarget(0, nullptr, -1, Dataspace::UNKNOWN,
- std::vector<IComposerClient::Rect>());
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->setClientTarget(0, nullptr, -1, Dataspace::UNKNOWN,
+ std::vector<IComposerClient::Rect>());
- execute();
+ execute();
}
/**
* Test IComposerClient::Command::SET_OUTPUT_BUFFER.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_OUTPUT_BUFFER) {
- if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
- GTEST_SUCCEED() << "no virtual display support";
- return;
- }
+ if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
+ GTEST_SUCCEED() << "no virtual display support";
+ return;
+ }
- Display display;
- PixelFormat format;
- ASSERT_NO_FATAL_FAILURE(display = mComposerClient->createVirtualDisplay(
- 64, 64, PixelFormat::IMPLEMENTATION_DEFINED,
- kBufferSlotCount, &format));
+ Display display;
+ PixelFormat format;
+ ASSERT_NO_FATAL_FAILURE(
+ display = mComposerClient->createVirtualDisplay(64, 64, PixelFormat::IMPLEMENTATION_DEFINED,
+ kBufferSlotCount, &format));
- const native_handle_t* handle;
- ASSERT_NO_FATAL_FAILURE(handle = allocate());
+ const native_handle_t* handle;
+ ASSERT_NO_FATAL_FAILURE(handle = allocate());
- mWriter->selectDisplay(display);
- mWriter->setOutputBuffer(0, handle, -1);
- execute();
+ mWriter->selectDisplay(display);
+ mWriter->setOutputBuffer(0, handle, -1);
+ execute();
}
/**
* Test IComposerClient::Command::VALIDATE_DISPLAY.
*/
TEST_F(GraphicsComposerHidlCommandTest, VALIDATE_DISPLAY) {
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->validateDisplay();
- execute();
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->validateDisplay();
+ execute();
}
/**
* Test IComposerClient::Command::ACCEPT_DISPLAY_CHANGES.
*/
TEST_F(GraphicsComposerHidlCommandTest, ACCEPT_DISPLAY_CHANGES) {
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->validateDisplay();
- mWriter->acceptDisplayChanges();
- execute();
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->validateDisplay();
+ mWriter->acceptDisplayChanges();
+ execute();
}
/**
* Test IComposerClient::Command::PRESENT_DISPLAY.
*/
TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY) {
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->validateDisplay();
- mWriter->presentDisplay();
- execute();
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->validateDisplay();
+ mWriter->presentDisplay();
+ execute();
}
/**
* Test IComposerClient::Command::SET_LAYER_CURSOR_POSITION.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_CURSOR_POSITION) {
- Layer layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(layer =
+ mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->selectLayer(layer);
- mWriter->setLayerCursorPosition(1, 1);
- mWriter->setLayerCursorPosition(0, 0);
- execute();
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerCursorPosition(1, 1);
+ mWriter->setLayerCursorPosition(0, 0);
+ execute();
}
/**
* Test IComposerClient::Command::SET_LAYER_BUFFER.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_BUFFER) {
- auto handle = allocate();
- ASSERT_NE(nullptr, handle);
+ auto handle = allocate();
+ ASSERT_NE(nullptr, handle);
- Layer layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(layer =
+ mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->selectLayer(layer);
- mWriter->setLayerBuffer(0, handle, -1);
- execute();
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBuffer(0, handle, -1);
+ execute();
}
/**
* Test IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SURFACE_DAMAGE) {
- Layer layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(layer =
+ mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
- IComposerClient::Rect empty{0, 0, 0, 0};
- IComposerClient::Rect unit{0, 0, 1, 1};
+ IComposerClient::Rect empty{0, 0, 0, 0};
+ IComposerClient::Rect unit{0, 0, 1, 1};
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->selectLayer(layer);
- mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, empty));
- mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, unit));
- mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>());
- execute();
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, empty));
+ mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, unit));
+ mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>());
+ execute();
}
/**
* Test IComposerClient::Command::SET_LAYER_BLEND_MODE.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_BLEND_MODE) {
- Layer layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(layer =
+ mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->selectLayer(layer);
- mWriter->setLayerBlendMode(IComposerClient::BlendMode::NONE);
- mWriter->setLayerBlendMode(IComposerClient::BlendMode::PREMULTIPLIED);
- mWriter->setLayerBlendMode(IComposerClient::BlendMode::COVERAGE);
- execute();
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBlendMode(IComposerClient::BlendMode::NONE);
+ mWriter->setLayerBlendMode(IComposerClient::BlendMode::PREMULTIPLIED);
+ mWriter->setLayerBlendMode(IComposerClient::BlendMode::COVERAGE);
+ execute();
}
/**
* Test IComposerClient::Command::SET_LAYER_COLOR.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_COLOR) {
- Layer layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(layer =
+ mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->selectLayer(layer);
- mWriter->setLayerColor(IComposerClient::Color{0xff, 0xff, 0xff, 0xff});
- mWriter->setLayerColor(IComposerClient::Color{0, 0, 0, 0});
- execute();
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerColor(IComposerClient::Color{0xff, 0xff, 0xff, 0xff});
+ mWriter->setLayerColor(IComposerClient::Color{0, 0, 0, 0});
+ execute();
}
/**
* Test IComposerClient::Command::SET_LAYER_COMPOSITION_TYPE.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_COMPOSITION_TYPE) {
- Layer layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(layer =
+ mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->selectLayer(layer);
- mWriter->setLayerCompositionType(IComposerClient::Composition::CLIENT);
- mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
- mWriter->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR);
- mWriter->setLayerCompositionType(IComposerClient::Composition::CURSOR);
- execute();
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerCompositionType(IComposerClient::Composition::CLIENT);
+ mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
+ mWriter->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR);
+ mWriter->setLayerCompositionType(IComposerClient::Composition::CURSOR);
+ execute();
}
/**
* Test IComposerClient::Command::SET_LAYER_DATASPACE.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_DATASPACE) {
- Layer layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(layer =
+ mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->selectLayer(layer);
- mWriter->setLayerDataspace(Dataspace::UNKNOWN);
- execute();
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerDataspace(Dataspace::UNKNOWN);
+ execute();
}
/**
* Test IComposerClient::Command::SET_LAYER_DISPLAY_FRAME.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_DISPLAY_FRAME) {
- Layer layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(layer =
+ mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->selectLayer(layer);
- mWriter->setLayerDisplayFrame(IComposerClient::Rect{0, 0, 1, 1});
- execute();
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerDisplayFrame(IComposerClient::Rect{0, 0, 1, 1});
+ execute();
}
/**
* Test IComposerClient::Command::SET_LAYER_PLANE_ALPHA.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PLANE_ALPHA) {
- Layer layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(layer =
+ mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->selectLayer(layer);
- mWriter->setLayerPlaneAlpha(0.0f);
- mWriter->setLayerPlaneAlpha(1.0f);
- execute();
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerPlaneAlpha(0.0f);
+ mWriter->setLayerPlaneAlpha(1.0f);
+ execute();
}
/**
* Test IComposerClient::Command::SET_LAYER_SIDEBAND_STREAM.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SIDEBAND_STREAM) {
- if (!mComposer->hasCapability(IComposer::Capability::SIDEBAND_STREAM)) {
- GTEST_SUCCEED() << "no sideband stream support";
- return;
- }
+ if (!mComposer->hasCapability(IComposer::Capability::SIDEBAND_STREAM)) {
+ GTEST_SUCCEED() << "no sideband stream support";
+ return;
+ }
- auto handle = allocate();
- ASSERT_NE(nullptr, handle);
+ auto handle = allocate();
+ ASSERT_NE(nullptr, handle);
- Layer layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(layer =
+ mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->selectLayer(layer);
- mWriter->setLayerSidebandStream(handle);
- execute();
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerSidebandStream(handle);
+ execute();
}
/**
* Test IComposerClient::Command::SET_LAYER_SOURCE_CROP.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SOURCE_CROP) {
- Layer layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(layer =
+ mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->selectLayer(layer);
- mWriter->setLayerSourceCrop(IComposerClient::FRect{0.0f, 0.0f, 1.0f, 1.0f});
- execute();
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerSourceCrop(IComposerClient::FRect{0.0f, 0.0f, 1.0f, 1.0f});
+ execute();
}
/**
* Test IComposerClient::Command::SET_LAYER_TRANSFORM.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_TRANSFORM) {
- Layer layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(layer =
+ mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->selectLayer(layer);
- mWriter->setLayerTransform(static_cast<Transform>(0));
- mWriter->setLayerTransform(Transform::FLIP_H);
- mWriter->setLayerTransform(Transform::FLIP_V);
- mWriter->setLayerTransform(Transform::ROT_90);
- mWriter->setLayerTransform(Transform::ROT_180);
- mWriter->setLayerTransform(Transform::ROT_270);
- mWriter->setLayerTransform(
- static_cast<Transform>(Transform::FLIP_H | Transform::ROT_90));
- mWriter->setLayerTransform(
- static_cast<Transform>(Transform::FLIP_V | Transform::ROT_90));
- execute();
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerTransform(static_cast<Transform>(0));
+ mWriter->setLayerTransform(Transform::FLIP_H);
+ mWriter->setLayerTransform(Transform::FLIP_V);
+ mWriter->setLayerTransform(Transform::ROT_90);
+ mWriter->setLayerTransform(Transform::ROT_180);
+ mWriter->setLayerTransform(Transform::ROT_270);
+ mWriter->setLayerTransform(static_cast<Transform>(Transform::FLIP_H | Transform::ROT_90));
+ mWriter->setLayerTransform(static_cast<Transform>(Transform::FLIP_V | Transform::ROT_90));
+ execute();
}
/**
* Test IComposerClient::Command::SET_LAYER_VISIBLE_REGION.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_VISIBLE_REGION) {
- Layer layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(layer =
+ mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
- IComposerClient::Rect empty{0, 0, 0, 0};
- IComposerClient::Rect unit{0, 0, 1, 1};
+ IComposerClient::Rect empty{0, 0, 0, 0};
+ IComposerClient::Rect unit{0, 0, 1, 1};
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->selectLayer(layer);
- mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, empty));
- mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, unit));
- mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>());
- execute();
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, empty));
+ mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, unit));
+ mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>());
+ execute();
}
/**
* Test IComposerClient::Command::SET_LAYER_Z_ORDER.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_Z_ORDER) {
- Layer layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(layer =
+ mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
- mWriter->selectDisplay(mPrimaryDisplay);
- mWriter->selectLayer(layer);
- mWriter->setLayerZOrder(10);
- mWriter->setLayerZOrder(0);
- execute();
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerZOrder(10);
+ mWriter->setLayerZOrder(0);
+ execute();
}
-} // namespace anonymous
-} // namespace tests
+} // namespace
+} // namespace vts
} // namespace V2_1
} // namespace composer
} // namespace graphics
@@ -704,7 +693,7 @@
} // namespace android
int main(int argc, char** argv) {
- using android::hardware::graphics::composer::V2_1::tests::GraphicsComposerHidlEnvironment;
+ using android::hardware::graphics::composer::V2_1::vts::GraphicsComposerHidlEnvironment;
::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv);
diff --git a/graphics/composer/2.2/default/Android.bp b/graphics/composer/2.2/default/Android.bp
new file mode 100644
index 0000000..906479e
--- /dev/null
+++ b/graphics/composer/2.2/default/Android.bp
@@ -0,0 +1,31 @@
+cc_binary {
+ name: "android.hardware.graphics.composer@2.2-service",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: ["service.cpp"],
+ init_rc: ["android.hardware.graphics.composer@2.2-service.rc"],
+ header_libs: [
+ "android.hardware.graphics.composer@2.2-passthrough",
+ ],
+ shared_libs: [
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.mapper@2.0",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libfmq",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwc2on1adapter",
+ "libhwc2onfbadapter",
+ "liblog",
+ "libsync",
+ "libutils",
+ ],
+ cflags: [
+ "-DLOG_TAG=\"ComposerHal\""
+ ],
+}
diff --git a/graphics/composer/2.2/default/OWNERS b/graphics/composer/2.2/default/OWNERS
new file mode 100644
index 0000000..4714be2
--- /dev/null
+++ b/graphics/composer/2.2/default/OWNERS
@@ -0,0 +1,5 @@
+# Graphics team
+courtneygo@google.com
+jessehall@google.com
+olv@google.com
+stoza@google.com
diff --git a/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc b/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc
new file mode 100644
index 0000000..a41d902
--- /dev/null
+++ b/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc
@@ -0,0 +1,6 @@
+service vendor.hwcomposer-2-2 /vendor/bin/hw/android.hardware.graphics.composer@2.2-service
+ class hal animation
+ user system
+ group graphics drmrpc
+ capabilities SYS_NICE
+ onrestart restart surfaceflinger
diff --git a/graphics/composer/2.2/default/service.cpp b/graphics/composer/2.2/default/service.cpp
new file mode 100644
index 0000000..8c5ef18
--- /dev/null
+++ b/graphics/composer/2.2/default/service.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include <sched.h>
+
+#include <android/hardware/graphics/composer/2.2/IComposer.h>
+#include <binder/ProcessState.h>
+#include <composer-passthrough/2.2/HwcLoader.h>
+#include <hidl/HidlTransportSupport.h>
+
+using android::hardware::graphics::composer::V2_2::IComposer;
+using android::hardware::graphics::composer::V2_2::passthrough::HwcLoader;
+
+int main() {
+ // the conventional HAL might start binder services
+ android::ProcessState::initWithDriver("/dev/vndbinder");
+ android::ProcessState::self()->setThreadPoolMaxThreadCount(4);
+ android::ProcessState::self()->startThreadPool();
+
+ // same as SF main thread
+ struct sched_param param = {0};
+ param.sched_priority = 2;
+ if (sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK, ¶m) != 0) {
+ ALOGE("Couldn't set SCHED_FIFO: %d", errno);
+ }
+
+ android::hardware::configureRpcThreadpool(4, true /* will join */);
+
+ android::sp<IComposer> composer = HwcLoader::load();
+ if (composer == nullptr) {
+ return 1;
+ }
+ if (composer->registerAsService() != android::NO_ERROR) {
+ ALOGE("failed to register service");
+ return 1;
+ }
+
+ android::hardware::joinRpcThreadpool();
+
+ ALOGE("service is terminating");
+ return 1;
+}
diff --git a/graphics/composer/2.2/utils/hal/Android.bp b/graphics/composer/2.2/utils/hal/Android.bp
new file mode 100644
index 0000000..10dcae4
--- /dev/null
+++ b/graphics/composer/2.2/utils/hal/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2018 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.
+
+cc_library_headers {
+ name: "android.hardware.graphics.composer@2.2-hal",
+ defaults: ["hidl_defaults"],
+ vendor_available: true,
+ shared_libs: [
+ "android.hardware.graphics.composer@2.2",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.graphics.composer@2.2",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.2-command-buffer",
+ "android.hardware.graphics.composer@2.1-hal",
+ ],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.2-command-buffer",
+ "android.hardware.graphics.composer@2.1-hal",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/Composer.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/Composer.h
new file mode 100644
index 0000000..58bbaa5
--- /dev/null
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/Composer.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "Composer.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/composer/2.2/IComposer.h>
+#include <composer-hal/2.1/Composer.h>
+#include <composer-hal/2.2/ComposerClient.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace hal {
+
+namespace detail {
+
+// ComposerImpl implements V2_*::IComposer on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerImpl : public V2_1::hal::detail::ComposerImpl<Interface, Hal> {
+ public:
+ static std::unique_ptr<ComposerImpl> create(std::unique_ptr<Hal> hal) {
+ return std::make_unique<ComposerImpl>(std::move(hal));
+ }
+
+ ComposerImpl(std::unique_ptr<Hal> hal) : BaseType2_1(std::move(hal)) {}
+
+ protected:
+ V2_1::IComposerClient* createClient() override {
+ auto client = ComposerClient::create(mHal.get());
+ if (!client) {
+ return nullptr;
+ }
+
+ auto clientDestroyed = [this]() { onClientDestroyed(); };
+ client->setOnClientDestroyed(clientDestroyed);
+
+ return client.release();
+ }
+
+ private:
+ using BaseType2_1 = V2_1::hal::detail::ComposerImpl<Interface, Hal>;
+ using BaseType2_1::mHal;
+ using BaseType2_1::onClientDestroyed;
+};
+
+} // namespace detail
+
+using Composer = detail::ComposerImpl<IComposer, ComposerHal>;
+
+} // namespace hal
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
new file mode 100644
index 0000000..d550f83
--- /dev/null
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerClient.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <composer-hal/2.1/ComposerClient.h>
+#include <composer-hal/2.2/ComposerCommandEngine.h>
+#include <composer-hal/2.2/ComposerHal.h>
+#include <composer-hal/2.2/ComposerResources.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace hal {
+
+namespace detail {
+
+// ComposerClientImpl implements V2_*::IComposerClient on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerClientImpl : public V2_1::hal::detail::ComposerClientImpl<Interface, Hal> {
+ public:
+ static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
+ auto client = std::make_unique<ComposerClientImpl>(hal);
+ return client->init() ? std::move(client) : nullptr;
+ }
+
+ ComposerClientImpl(Hal* hal) : BaseType2_1(hal) {}
+
+ // IComposerClient 2.2 interface
+
+ Return<void> getPerFrameMetadataKeys(
+ Display display, IComposerClient::getPerFrameMetadataKeys_cb hidl_cb) override {
+ std::vector<IComposerClient::PerFrameMetadataKey> keys;
+ Error error = mHal->getPerFrameMetadataKeys(display, &keys);
+ hidl_cb(error, keys);
+ return Void();
+ }
+
+ Return<void> getReadbackBufferAttributes(
+ Display display, IComposerClient::getReadbackBufferAttributes_cb hidl_cb) override {
+ PixelFormat format = static_cast<PixelFormat>(0);
+ Dataspace dataspace = Dataspace::UNKNOWN;
+ Error error = mHal->getReadbackBufferAttributes(display, &format, &dataspace);
+ hidl_cb(error, format, dataspace);
+ return Void();
+ }
+
+ Return<void> getReadbackBufferFence(
+ Display display, IComposerClient::getReadbackBufferFence_cb hidl_cb) override {
+ base::unique_fd fenceFd;
+ Error error = mHal->getReadbackBufferFence(display, &fenceFd);
+ if (error != Error::NONE) {
+ hidl_cb(error, nullptr);
+ return Void();
+ }
+
+ NATIVE_HANDLE_DECLARE_STORAGE(fenceStorage, 1, 0);
+ hidl_cb(error, getFenceHandle(fenceFd, fenceStorage));
+ return Void();
+ }
+
+ Return<Error> setReadbackBuffer(Display display, const hidl_handle& buffer,
+ const hidl_handle& releaseFence) override {
+ base::unique_fd fenceFd;
+ Error error = getFenceFd(releaseFence, &fenceFd);
+ if (error != Error::NONE) {
+ return error;
+ }
+
+ auto resources = static_cast<ComposerResources*>(mResources.get());
+ const native_handle_t* readbackBuffer;
+ ComposerResources::ReplacedBufferHandle replacedReadbackBuffer;
+ error = resources->getDisplayReadbackBuffer(display, buffer.getNativeHandle(),
+ &readbackBuffer, &replacedReadbackBuffer);
+ if (error != Error::NONE) {
+ return error;
+ }
+
+ return mHal->setReadbackBuffer(display, readbackBuffer, std::move(fenceFd));
+ }
+
+ Return<Error> setPowerMode_2_2(Display display, IComposerClient::PowerMode mode) override {
+ return mHal->setPowerMode_2_2(display, mode);
+ }
+
+ protected:
+ std::unique_ptr<V2_1::hal::ComposerResources> createResources() override {
+ return ComposerResources::create();
+ }
+
+ std::unique_ptr<V2_1::hal::ComposerCommandEngine> createCommandEngine() override {
+ return std::make_unique<ComposerCommandEngine>(
+ mHal, static_cast<ComposerResources*>(mResources.get()));
+ }
+
+ // convert fenceFd to or from hidl_handle
+ static Error getFenceFd(const hidl_handle& fenceHandle, base::unique_fd* outFenceFd) {
+ auto handle = fenceHandle.getNativeHandle();
+ if (handle && handle->numFds > 1) {
+ ALOGE("invalid fence handle with %d fds", handle->numFds);
+ return Error::BAD_PARAMETER;
+ }
+
+ int fenceFd = (handle && handle->numFds == 1) ? handle->data[0] : -1;
+ if (fenceFd >= 0) {
+ fenceFd = dup(fenceFd);
+ if (fenceFd < 0) {
+ return Error::NO_RESOURCES;
+ }
+ }
+
+ outFenceFd->reset(fenceFd);
+
+ return Error::NONE;
+ }
+
+ static hidl_handle getFenceHandle(const base::unique_fd& fenceFd, char* handleStorage) {
+ native_handle_t* handle = nullptr;
+ if (fenceFd >= 0) {
+ handle = native_handle_init(handleStorage, 1, 0);
+ handle->data[0] = fenceFd;
+ }
+
+ return hidl_handle(handle);
+ }
+
+ private:
+ using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
+ using BaseType2_1::mHal;
+ using BaseType2_1::mResources;
+};
+
+} // namespace detail
+
+using ComposerClient = detail::ComposerClientImpl<IComposerClient, ComposerHal>;
+
+} // namespace hal
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
new file mode 100644
index 0000000..adcac46
--- /dev/null
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerCommandEngine.h included without LOG_TAG"
+#endif
+
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <composer-hal/2.1/ComposerCommandEngine.h>
+#include <composer-hal/2.2/ComposerHal.h>
+#include <composer-hal/2.2/ComposerResources.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace hal {
+
+class ComposerCommandEngine : public V2_1::hal::ComposerCommandEngine {
+ public:
+ ComposerCommandEngine(ComposerHal* hal, ComposerResources* resources)
+ : BaseType2_1(hal, resources), mHal(hal) {}
+
+ protected:
+ bool executeCommand(V2_1::IComposerClient::Command command, uint16_t length) override {
+ switch (static_cast<IComposerClient::Command>(command)) {
+ case IComposerClient::Command::SET_PER_FRAME_METADATA:
+ return executeSetPerFrameMetadata(length);
+ case IComposerClient::Command::SET_LAYER_FLOAT_COLOR:
+ return executeSetLayerFloatColor(length);
+ default:
+ return BaseType2_1::executeCommand(command, length);
+ }
+ }
+
+ bool executeSetPerFrameMetadata(uint16_t length) {
+ // (key, value) pairs
+ if (length % 2 != 0) {
+ return false;
+ }
+
+ std::vector<IComposerClient::PerFrameMetadata> metadata;
+ metadata.reserve(length / 2);
+ while (length > 0) {
+ metadata.emplace_back(IComposerClient::PerFrameMetadata{
+ static_cast<IComposerClient::PerFrameMetadataKey>(readSigned()), readFloat()});
+ length -= 2;
+ }
+
+ auto err = mHal->setPerFrameMetadata(mCurrentDisplay, metadata);
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ bool executeSetLayerFloatColor(uint16_t length) {
+ if (length != CommandWriterBase::kSetLayerFloatColorLength) {
+ return false;
+ }
+
+ auto err = mHal->setLayerFloatColor(mCurrentDisplay, mCurrentLayer, readFloatColor());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ IComposerClient::FloatColor readFloatColor() {
+ return IComposerClient::FloatColor{readFloat(), readFloat(), readFloat(), readFloat()};
+ }
+
+ private:
+ using BaseType2_1 = V2_1::hal::ComposerCommandEngine;
+ using BaseType2_1::mWriter;
+
+ ComposerHal* mHal;
+};
+
+} // namespace hal
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerHal.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerHal.h
new file mode 100644
index 0000000..30b3643
--- /dev/null
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerHal.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <android/hardware/graphics/composer/2.2/IComposer.h>
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <composer-hal/2.1/ComposerHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace hal {
+
+using common::V1_0::Dataspace;
+using common::V1_0::PixelFormat;
+using V2_1::Display;
+using V2_1::Error;
+using V2_1::Layer;
+
+class ComposerHal : public V2_1::hal::ComposerHal {
+ public:
+ // superceded by setPowerMode_2_2
+ Error setPowerMode(Display display, V2_1::IComposerClient::PowerMode mode) override {
+ return setPowerMode_2_2(display, static_cast<IComposerClient::PowerMode>(mode));
+ }
+
+ virtual Error getPerFrameMetadataKeys(
+ Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) = 0;
+ virtual Error setPerFrameMetadata(
+ Display display, const std::vector<IComposerClient::PerFrameMetadata>& metadata) = 0;
+
+ virtual Error getReadbackBufferAttributes(Display display, PixelFormat* outFormat,
+ Dataspace* outDataspace) = 0;
+ virtual Error setReadbackBuffer(Display display, const native_handle_t* bufferHandle,
+ base::unique_fd fenceFd) = 0;
+ virtual Error getReadbackBufferFence(Display display, base::unique_fd* outFenceFd) = 0;
+
+ virtual Error setPowerMode_2_2(Display display, IComposerClient::PowerMode mode) = 0;
+
+ virtual Error setLayerFloatColor(Display display, Layer layer,
+ IComposerClient::FloatColor color) = 0;
+};
+
+} // namespace hal
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h
new file mode 100644
index 0000000..85b6651
--- /dev/null
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerResources.h included without LOG_TAG"
+#endif
+
+#include <composer-hal/2.1/ComposerResources.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace hal {
+
+using V2_1::hal::ComposerHandleCache;
+using V2_1::hal::ComposerHandleImporter;
+
+class ComposerDisplayResource : public V2_1::hal::ComposerDisplayResource {
+ public:
+ ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
+ uint32_t outputBufferCacheSize)
+ : V2_1::hal::ComposerDisplayResource(type, importer, outputBufferCacheSize),
+ mReadbackBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, 1) {}
+
+ Error getReadbackBuffer(const native_handle_t* inHandle, const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle) {
+ const uint32_t slot = 0;
+ const bool fromCache = false;
+ return mReadbackBufferCache.getHandle(slot, fromCache, inHandle, outHandle,
+ outReplacedHandle);
+ }
+
+ protected:
+ ComposerHandleCache mReadbackBufferCache;
+};
+
+class ComposerResources : public V2_1::hal::ComposerResources {
+ public:
+ static std::unique_ptr<ComposerResources> create() {
+ auto resources = std::make_unique<ComposerResources>();
+ return resources->init() ? std::move(resources) : nullptr;
+ }
+
+ Error getDisplayReadbackBuffer(Display display, const native_handle_t* rawHandle,
+ const native_handle_t** outHandle,
+ ReplacedBufferHandle* outReplacedHandle) {
+ // import buffer
+ const native_handle_t* importedHandle;
+ Error error = mImporter.importBuffer(rawHandle, &importedHandle);
+ if (error != Error::NONE) {
+ return error;
+ }
+
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+
+ auto iter = mDisplayResources.find(display);
+ if (iter == mDisplayResources.end()) {
+ mImporter.freeBuffer(importedHandle);
+ return Error::BAD_DISPLAY;
+ }
+ ComposerDisplayResource& displayResource =
+ *static_cast<ComposerDisplayResource*>(iter->second.get());
+
+ // update cache
+ const native_handle_t* replacedHandle;
+ error = displayResource.getReadbackBuffer(importedHandle, outHandle, &replacedHandle);
+ if (error != Error::NONE) {
+ mImporter.freeBuffer(importedHandle);
+ return error;
+ }
+
+ outReplacedHandle->reset(&mImporter, replacedHandle);
+ return Error::NONE;
+ }
+
+ protected:
+ std::unique_ptr<V2_1::hal::ComposerDisplayResource> createDisplayResource(
+ ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) override {
+ return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
+ }
+};
+
+} // namespace hal
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/utils/passthrough/Android.bp b/graphics/composer/2.2/utils/passthrough/Android.bp
new file mode 100644
index 0000000..318ce91
--- /dev/null
+++ b/graphics/composer/2.2/utils/passthrough/Android.bp
@@ -0,0 +1,14 @@
+cc_library_headers {
+ name: "android.hardware.graphics.composer@2.2-passthrough",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-passthrough",
+ "android.hardware.graphics.composer@2.2-hal",
+ ],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.1-passthrough",
+ "android.hardware.graphics.composer@2.2-hal",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h b/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h
new file mode 100644
index 0000000..b251351
--- /dev/null
+++ b/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "HwcHal.h included without LOG_TAG"
+#endif
+
+#include <type_traits>
+
+#include <composer-hal/2.2/ComposerHal.h>
+#include <composer-passthrough/2.1/HwcHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace passthrough {
+
+namespace detail {
+
+using common::V1_0::Dataspace;
+using common::V1_0::PixelFormat;
+using V2_1::Display;
+using V2_1::Error;
+using V2_1::Layer;
+
+// HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2
+template <typename Hal>
+class HwcHalImpl : public V2_1::passthrough::detail::HwcHalImpl<Hal> {
+ public:
+ // XXX when can we return Error::UNSUPPORTED?
+
+ Error getPerFrameMetadataKeys(
+ Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) override {
+ if (!mDispatch.getPerFrameMetadataKeys) {
+ return Error::UNSUPPORTED;
+ }
+
+ uint32_t count = 0;
+ int32_t error = mDispatch.getPerFrameMetadataKeys(mDevice, display, &count, nullptr);
+ if (error != HWC2_ERROR_NONE) {
+ return static_cast<Error>(error);
+ }
+
+ std::vector<IComposerClient::PerFrameMetadataKey> keys(count);
+ error = mDispatch.getPerFrameMetadataKeys(
+ mDevice, display, &count,
+ reinterpret_cast<std::underlying_type<IComposerClient::PerFrameMetadataKey>::type*>(
+ keys.data()));
+ if (error != HWC2_ERROR_NONE) {
+ return static_cast<Error>(error);
+ }
+
+ keys.resize(count);
+ *outKeys = std::move(keys);
+ return Error::NONE;
+ }
+
+ Error setPerFrameMetadata(
+ Display display, const std::vector<IComposerClient::PerFrameMetadata>& metadata) override {
+ if (!mDispatch.setPerFrameMetadata) {
+ return Error::UNSUPPORTED;
+ }
+
+ std::vector<int32_t> keys;
+ std::vector<float> values;
+ keys.reserve(metadata.size());
+ values.reserve(metadata.size());
+ for (const auto& m : metadata) {
+ keys.push_back(static_cast<int32_t>(m.key));
+ values.push_back(m.value);
+ }
+
+ int32_t error = mDispatch.setPerFrameMetadata(mDevice, display, metadata.size(),
+ keys.data(), values.data());
+ return static_cast<Error>(error);
+ }
+
+ Error getReadbackBufferAttributes(Display display, PixelFormat* outFormat,
+ Dataspace* outDataspace) override {
+ if (!mDispatch.getReadbackBufferAttributes) {
+ return Error::UNSUPPORTED;
+ }
+
+ int32_t format = 0;
+ int32_t dataspace = 0;
+ int32_t error =
+ mDispatch.getReadbackBufferAttributes(mDevice, display, &format, &dataspace);
+ if (error == HWC2_ERROR_NONE) {
+ *outFormat = static_cast<PixelFormat>(format);
+ *outDataspace = static_cast<Dataspace>(dataspace);
+ }
+ return static_cast<Error>(error);
+ }
+
+ Error setReadbackBuffer(Display display, const native_handle_t* bufferHandle,
+ base::unique_fd fenceFd) override {
+ if (!mDispatch.setReadbackBuffer) {
+ return Error::UNSUPPORTED;
+ }
+
+ int32_t error =
+ mDispatch.setReadbackBuffer(mDevice, display, bufferHandle, fenceFd.release());
+ return static_cast<Error>(error);
+ }
+
+ Error getReadbackBufferFence(Display display, base::unique_fd* outFenceFd) override {
+ if (!mDispatch.getReadbackBufferFence) {
+ return Error::UNSUPPORTED;
+ }
+
+ int32_t fenceFd = -1;
+ int32_t error = mDispatch.getReadbackBufferFence(mDevice, display, &fenceFd);
+ outFenceFd->reset(fenceFd);
+ return static_cast<Error>(error);
+ }
+
+ Error setPowerMode_2_2(Display display, IComposerClient::PowerMode mode) override {
+ if (mode == IComposerClient::PowerMode::ON_SUSPEND) {
+ return Error::UNSUPPORTED;
+ }
+ return setPowerMode(display, static_cast<V2_1::IComposerClient::PowerMode>(mode));
+ }
+
+ Error setLayerFloatColor(Display display, Layer layer,
+ IComposerClient::FloatColor color) override {
+ if (!mDispatch.setLayerFloatColor) {
+ return Error::UNSUPPORTED;
+ }
+
+ int32_t error = mDispatch.setLayerFloatColor(
+ mDevice, display, layer, hwc_float_color{color.r, color.g, color.b, color.a});
+ return static_cast<Error>(error);
+ }
+
+ protected:
+ template <typename T>
+ bool initOptionalDispatch(hwc2_function_descriptor_t desc, T* outPfn) {
+ auto pfn = mDevice->getFunction(mDevice, desc);
+ if (pfn) {
+ *outPfn = reinterpret_cast<T>(pfn);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ bool initDispatch() override {
+ if (!BaseType2_1::initDispatch()) {
+ return false;
+ }
+
+ initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_FLOAT_COLOR, &mDispatch.setLayerFloatColor);
+
+ initOptionalDispatch(HWC2_FUNCTION_SET_PER_FRAME_METADATA, &mDispatch.setPerFrameMetadata);
+ initOptionalDispatch(HWC2_FUNCTION_GET_PER_FRAME_METADATA_KEYS,
+ &mDispatch.getPerFrameMetadataKeys);
+
+ initOptionalDispatch(HWC2_FUNCTION_SET_READBACK_BUFFER, &mDispatch.setReadbackBuffer);
+ initOptionalDispatch(HWC2_FUNCTION_GET_READBACK_BUFFER_ATTRIBUTES,
+ &mDispatch.getReadbackBufferAttributes);
+ initOptionalDispatch(HWC2_FUNCTION_GET_READBACK_BUFFER_FENCE,
+ &mDispatch.getReadbackBufferFence);
+
+ return true;
+ }
+
+ struct {
+ HWC2_PFN_SET_LAYER_FLOAT_COLOR setLayerFloatColor;
+ HWC2_PFN_SET_PER_FRAME_METADATA setPerFrameMetadata;
+ HWC2_PFN_GET_PER_FRAME_METADATA_KEYS getPerFrameMetadataKeys;
+ HWC2_PFN_SET_READBACK_BUFFER setReadbackBuffer;
+ HWC2_PFN_GET_READBACK_BUFFER_ATTRIBUTES getReadbackBufferAttributes;
+ HWC2_PFN_GET_READBACK_BUFFER_FENCE getReadbackBufferFence;
+ } mDispatch = {};
+
+ private:
+ using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl<Hal>;
+ using BaseType2_1::mDevice;
+ using BaseType2_1::setPowerMode;
+};
+
+} // namespace detail
+
+using HwcHal = detail::HwcHalImpl<hal::ComposerHal>;
+
+} // namespace passthrough
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcLoader.h b/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcLoader.h
new file mode 100644
index 0000000..cb4a238
--- /dev/null
+++ b/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcLoader.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "HwcLoader.h included without LOG_TAG"
+#endif
+
+#include <composer-hal/2.2/Composer.h>
+#include <composer-hal/2.2/ComposerHal.h>
+#include <composer-passthrough/2.1/HwcLoader.h>
+#include <composer-passthrough/2.2/HwcHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace passthrough {
+
+class HwcLoader : public V2_1::passthrough::HwcLoader {
+ public:
+ static IComposer* load() {
+ const hw_module_t* module = loadModule();
+ if (!module) {
+ return nullptr;
+ }
+
+ auto hal = createHalWithAdapter(module);
+ if (!hal) {
+ return nullptr;
+ }
+
+ return createComposer(std::move(hal)).release();
+ }
+
+ // create a ComposerHal instance
+ static std::unique_ptr<hal::ComposerHal> createHal(const hw_module_t* module) {
+ auto hal = std::make_unique<HwcHal>();
+ return hal->initWithModule(module) ? std::move(hal) : nullptr;
+ }
+
+ // create a ComposerHal instance, insert an adapter if necessary
+ static std::unique_ptr<hal::ComposerHal> createHalWithAdapter(const hw_module_t* module) {
+ bool adapted;
+ hwc2_device_t* device = openDeviceWithAdapter(module, &adapted);
+ if (!device) {
+ return nullptr;
+ }
+ auto hal = std::make_unique<HwcHal>();
+ return hal->initWithDevice(std::move(device), !adapted) ? std::move(hal) : nullptr;
+ }
+
+ // create an IComposer instance
+ static std::unique_ptr<IComposer> createComposer(std::unique_ptr<hal::ComposerHal> hal) {
+ return hal::Composer::create(std::move(hal));
+ }
+};
+
+} // namespace passthrough
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
new file mode 100644
index 0000000..641fdcb
--- /dev/null
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2018 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.
+//
+
+cc_library_static {
+ name: "android.hardware.graphics.composer@2.2-vts",
+ defaults: ["hidl_defaults"],
+ srcs: [
+ "ComposerVts.cpp",
+ ],
+ static_libs: [
+ "VtsHalHidlTargetTestBase",
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.1-vts",
+ "android.hardware.graphics.composer@2.2",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ "android.hardware.graphics.composer@2.2-command-buffer",
+ ],
+ cflags: [
+ "-O0",
+ "-g",
+ "-DLOG_TAG=\"ComposerVts\"",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerTestUtils.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
similarity index 96%
rename from graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerTestUtils.cpp
rename to graphics/composer/2.2/utils/vts/ComposerVts.cpp
index 00946ce..b536f67 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerTestUtils.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -14,22 +14,22 @@
* limitations under the License.
*/
-#include <VtsHalHidlTargetTestBase.h>
-#include <hidl/HidlTransportUtils.h>
+#include <composer-vts/2.2/ComposerVts.h>
+#include <VtsHalHidlTargetTestBase.h>
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
-#include "2.2/VtsHalGraphicsComposerTestUtils.h"
+#include <hidl/HidlTransportUtils.h>
namespace android {
namespace hardware {
namespace graphics {
namespace composer {
namespace V2_2 {
-namespace tests {
+namespace vts {
-using android::hardware::graphics::composer::V2_2::IComposerClient;
-using android::hardware::details::getDescriptor;
using android::hardware::details::canCastInterface;
+using android::hardware::details::getDescriptor;
+using android::hardware::graphics::composer::V2_2::IComposerClient;
std::unique_ptr<ComposerClient_v2_2> Composer_v2_2::createClient_v2_2() {
std::unique_ptr<ComposerClient_v2_2> client;
@@ -56,7 +56,7 @@
return keys;
}
-void ComposerClient_v2_2::execute_v2_2(V2_1::tests::TestCommandReader* reader,
+void ComposerClient_v2_2::execute_v2_2(V2_1::vts::TestCommandReader* reader,
V2_2::CommandWriterBase* writer) {
bool queueChanged = false;
uint32_t commandLength = 0;
@@ -119,7 +119,7 @@
*outFence = 0;
}
-} // namespace tests
+} // namespace vts
} // namespace V2_2
} // namespace composer
} // namespace graphics
diff --git a/graphics/composer/2.2/vts/functional/include/2.2/VtsHalGraphicsComposerTestUtils.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
similarity index 82%
rename from graphics/composer/2.2/vts/functional/include/2.2/VtsHalGraphicsComposerTestUtils.h
rename to graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
index c5756ed..eced69f 100644
--- a/graphics/composer/2.2/vts/functional/include/2.2/VtsHalGraphicsComposerTestUtils.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
@@ -22,11 +22,11 @@
#include <unordered_set>
#include <vector>
-#include <VtsHalGraphicsComposerTestUtils.h>
#include <VtsHalHidlTargetTestBase.h>
#include <android/hardware/graphics/composer/2.2/IComposer.h>
#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <composer-vts/2.1/ComposerVts.h>
#include <utils/StrongPointer.h>
namespace android {
@@ -34,7 +34,7 @@
namespace graphics {
namespace composer {
namespace V2_2 {
-namespace tests {
+namespace vts {
using android::hardware::graphics::common::V1_0::ColorMode;
using android::hardware::graphics::common::V1_0::Dataspace;
@@ -47,22 +47,22 @@
// Only thing I need for Composer_v2_2 is to create a v2_2 ComposerClient
// Everything else is the same
-class Composer_v2_2 : public V2_1::tests::Composer {
+class Composer_v2_2 : public V2_1::vts::Composer {
public:
- Composer_v2_2() : V2_1::tests::Composer(){};
- explicit Composer_v2_2(const std::string& name) : V2_1::tests::Composer(name){};
+ Composer_v2_2() : V2_1::vts::Composer(){};
+ explicit Composer_v2_2(const std::string& name) : V2_1::vts::Composer(name){};
std::unique_ptr<ComposerClient_v2_2> createClient_v2_2();
};
// A wrapper to IComposerClient.
class ComposerClient_v2_2
- : public android::hardware::graphics::composer::V2_1::tests::ComposerClient {
+ : public android::hardware::graphics::composer::V2_1::vts::ComposerClient {
public:
ComposerClient_v2_2(const sp<IComposerClient>& client)
- : V2_1::tests::ComposerClient(client), mClient_v2_2(client){};
+ : V2_1::vts::ComposerClient(client), mClient_v2_2(client){};
- void execute_v2_2(V2_1::tests::TestCommandReader* reader, V2_2::CommandWriterBase* writer);
+ void execute_v2_2(V2_1::vts::TestCommandReader* reader, V2_2::CommandWriterBase* writer);
std::vector<IComposerClient::PerFrameMetadataKey> getPerFrameMetadataKeys(Display display);
@@ -76,7 +76,7 @@
sp<V2_2::IComposerClient> mClient_v2_2;
};
-} // namespace tests
+} // namespace vts
} // namespace V2_2
} // namespace composer
} // namespace graphics
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index 78322a1..7747900 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -14,37 +14,6 @@
// limitations under the License.
//
-cc_library_static {
- name: "libVtsHalGraphicsComposerTestUtils@2.2",
- defaults: ["hidl_defaults"],
- srcs: [
- "VtsHalGraphicsComposerTestUtils.cpp",
- ],
- shared_libs: [
- "android.hardware.graphics.composer@2.1",
- "android.hardware.graphics.composer@2.2",
- "libfmq",
- "libsync",
- ],
- static_libs: [
- "libVtsHalGraphicsComposerTestUtils",
- "VtsHalHidlTargetTestBase",
- ],
- header_libs: [
- "android.hardware.graphics.composer@2.1-command-buffer",
- "android.hardware.graphics.composer@2.2-command-buffer",
- ],
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-O0",
- "-g",
- "-DLOG_TAG=\"GraphicsComposerTestUtils@2.2\"",
- ],
- export_include_dirs: ["include"],
-}
-
cc_test {
name: "VtsHalGraphicsComposerV2_2TargetTest",
defaults: ["VtsHalTargetTestDefaults"],
@@ -58,14 +27,13 @@
],
static_libs: [
"android.hardware.graphics.allocator@2.0",
- "android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.1-vts",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.2-vts",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.0-vts",
"android.hardware.graphics.mapper@2.1",
- "libVtsHalGraphicsComposerTestUtils",
- "libVtsHalGraphicsComposerTestUtils@2.2",
- "libnativehelper",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
index 6fbdd3c..c494329 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -16,23 +16,20 @@
#define LOG_TAG "graphics_composer_hidl_hal_test@2.2"
+#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <composer-vts/2.1/GraphicsComposerCallback.h>
+#include <composer-vts/2.1/TestCommandReader.h>
+#include <composer-vts/2.2/ComposerVts.h>
#include <mapper-vts/2.0/MapperVts.h>
-#include <sync/sync.h>
-#include "2.2/VtsHalGraphicsComposerTestUtils.h"
-#include "GraphicsComposerCallback.h"
-#include "TestCommandReader.h"
-#include "VtsHalGraphicsComposerTestUtils.h"
-
-#include <VtsHalHidlTargetTestBase.h>
namespace android {
namespace hardware {
namespace graphics {
namespace composer {
namespace V2_2 {
-namespace tests {
+namespace vts {
namespace {
using android::hardware::graphics::common::V1_0::BufferUsage;
@@ -71,7 +68,7 @@
GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient_v2_2());
- mComposerCallback = new V2_1::tests::GraphicsComposerCallback;
+ mComposerCallback = new V2_1::vts::GraphicsComposerCallback;
mComposerClient->registerCallback(mComposerCallback);
// assume the first display is primary and is never removed
@@ -95,7 +92,7 @@
std::unique_ptr<Composer_v2_2> mComposer;
std::unique_ptr<ComposerClient_v2_2> mComposerClient;
- sp<V2_1::tests::GraphicsComposerCallback> mComposerCallback;
+ sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
// the first display and is assumed never to be removed
Display mPrimaryDisplay;
@@ -122,7 +119,7 @@
ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
mWriter = std::make_unique<V2_2::CommandWriterBase>(1024);
- mReader = std::make_unique<V2_1::tests::TestCommandReader>();
+ mReader = std::make_unique<V2_1::vts::TestCommandReader>();
}
void TearDown() override { ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown()); }
@@ -142,7 +139,7 @@
void execute() { mComposerClient->execute_v2_2(mReader.get(), mWriter.get()); }
std::unique_ptr<V2_2::CommandWriterBase> mWriter;
- std::unique_ptr<V2_1::tests::TestCommandReader> mReader;
+ std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
private:
std::unique_ptr<Gralloc> mGralloc;
@@ -239,7 +236,7 @@
}
} // namespace
-} // namespace tests
+} // namespace vts
} // namespace V2_2
} // namespace composer
} // namespace graphics
@@ -247,7 +244,7 @@
} // namespace android
int main(int argc, char** argv) {
- using android::hardware::graphics::composer::V2_2::tests::GraphicsComposerHidlEnvironment;
+ using android::hardware::graphics::composer::V2_2::vts::GraphicsComposerHidlEnvironment;
::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv);
diff --git a/health/1.0/vts/functional/VtsHalHealthV1_0TargetTest.cpp b/health/1.0/vts/functional/VtsHalHealthV1_0TargetTest.cpp
index 324eb9f..335d15d 100644
--- a/health/1.0/vts/functional/VtsHalHealthV1_0TargetTest.cpp
+++ b/health/1.0/vts/functional/VtsHalHealthV1_0TargetTest.cpp
@@ -19,7 +19,9 @@
#include <android/hardware/health/1.0/IHealth.h>
#include <android/hardware/health/1.0/types.h>
#include <log/log.h>
+
#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
using HealthConfig = ::android::hardware::health::V1_0::HealthConfig;
using HealthInfo = ::android::hardware::health::V1_0::HealthInfo;
@@ -28,10 +30,25 @@
using ::android::sp;
+// Test environment for Health HIDL HAL.
+class HealthHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static HealthHidlEnvironment* Instance() {
+ static HealthHidlEnvironment* instance = new HealthHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<IHealth>(); }
+ private:
+ HealthHidlEnvironment() {}
+};
+
class HealthHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
virtual void SetUp() override {
- health = ::testing::VtsHalHidlTargetTestBase::getService<IHealth>();
+ health = ::testing::VtsHalHidlTargetTestBase::getService<IHealth>(
+ HealthHidlEnvironment::Instance()->getServiceName<IHealth>());
ASSERT_NE(health, nullptr);
health->init(config,
[&](const auto& halConfigOut) { config = halConfigOut; });
@@ -57,7 +74,9 @@
}
int main(int argc, char **argv) {
+ ::testing::AddGlobalTestEnvironment(HealthHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
+ HealthHidlEnvironment::Instance()->init(&argc, argv);
int status = RUN_ALL_TESTS();
ALOGI("Test result = %d", status);
return status;
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index e33ee77..54dd14a 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -14,22 +14,49 @@
// limitations under the License.
//
+cc_library_static {
+ name: "VtsHalNeuralnetworksTest_utils",
+ srcs: [
+ "Callbacks.cpp",
+ "Models.cpp",
+ "GeneratedTestHarness.cpp",
+ ],
+ defaults: ["VtsHalTargetTestDefaults"],
+ export_include_dirs: ["."],
+ static_libs: [
+ "android.hardware.neuralnetworks@1.0",
+ "android.hardware.neuralnetworks@1.1",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libhidlmemory",
+ "libneuralnetworks_utils",
+ ],
+ header_libs: [
+ "libneuralnetworks_headers",
+ "libneuralnetworks_generated_test_harness_headers",
+ "libneuralnetworks_generated_tests",
+ ],
+}
+
cc_test {
name: "VtsHalNeuralnetworksV1_0TargetTest",
srcs: [
- "Callbacks.cpp",
- "GeneratedTestHarness.cpp",
- "Models.cpp",
- "VtsHalNeuralnetworksV1_0TargetTest.cpp",
+ "VtsHalNeuralnetworksV1_0.cpp",
+ "VtsHalNeuralnetworksV1_0BasicTest.cpp",
+ "VtsHalNeuralnetworksV1_0GeneratedTest.cpp",
],
defaults: ["VtsHalTargetTestDefaults"],
static_libs: [
"android.hardware.neuralnetworks@1.0",
+ "android.hardware.neuralnetworks@1.1",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"libhidlmemory",
+ "libneuralnetworks_utils",
+ "VtsHalNeuralnetworksTest_utils",
],
header_libs: [
+ "libneuralnetworks_headers",
"libneuralnetworks_generated_test_harness_headers",
"libneuralnetworks_generated_tests",
],
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index d740b5f..f0ce938 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -16,9 +16,15 @@
#include "Callbacks.h"
#include "TestHarness.h"
-#include "VtsHalNeuralnetworksV1_0TargetTest.h"
+#include "Utils.h"
#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.0/IDevice.h>
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
#include <iostream>
@@ -26,11 +32,6 @@
namespace android {
namespace hardware {
namespace neuralnetworks {
-namespace V1_0 {
-namespace vts {
-namespace functional {
-// allocator helper
-hidl_memory allocateSharedMemory(int64_t size, const std::string& type = "ashmem");
namespace generated_tests {
using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
@@ -64,54 +65,11 @@
// Top level driver for models and examples generated by test_generator.py
// Test driver for those generated from ml/nn/runtime/test/spec
-void Execute(const sp<IDevice>& device, std::function<Model(void)> create_model,
- std::function<bool(int)> is_ignored,
- const std::vector<MixedTypedExampleType>& examples) {
+void EvaluatePreparedModel(sp<IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
+ const std::vector<MixedTypedExampleType>& examples,
+ float fpRange = 1e-5f) {
const uint32_t INPUT = 0;
const uint32_t OUTPUT = 1;
- Model model = create_model();
-
- // see if service can handle model
- ErrorStatus supportedStatus;
- bool fullySupportsModel = false;
- Return<void> supportedCall = device->getSupportedOperations(
- model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
- supportedStatus = status;
- ASSERT_NE(0ul, supported.size());
- fullySupportsModel =
- std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
- });
- ASSERT_TRUE(supportedCall.isOk());
- ASSERT_EQ(ErrorStatus::NONE, supportedStatus);
-
- // launch prepare model
- sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
- ASSERT_NE(nullptr, preparedModelCallback.get());
- Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
- ASSERT_TRUE(prepareLaunchStatus.isOk());
-
- // retrieve prepared model
- preparedModelCallback->wait();
- ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
- sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
- if (fullySupportsModel) {
- EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
- } else {
- EXPECT_TRUE(prepareReturnStatus == ErrorStatus::NONE ||
- prepareReturnStatus == ErrorStatus::GENERAL_FAILURE);
- }
-
- // early termination if vendor service cannot fully prepare model
- if (!fullySupportsModel && prepareReturnStatus == ErrorStatus::GENERAL_FAILURE) {
- ASSERT_EQ(nullptr, preparedModel.get());
- LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
- "prepare model that it does not support.";
- std::cout << "[ ] Early termination of test because vendor service cannot "
- "prepare model that it does not support."
- << std::endl;
- return;
- }
- ASSERT_NE(nullptr, preparedModel.get());
int example_no = 1;
for (auto& example : examples) {
@@ -167,8 +125,8 @@
offset += i.location.length;
}
}
- std::vector<hidl_memory> pools = {allocateSharedMemory(inputSize),
- allocateSharedMemory(outputSize)};
+ std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
+ nn::allocateSharedMemory(outputSize)};
ASSERT_NE(0ull, pools[INPUT].size());
ASSERT_NE(0ull, pools[OUTPUT].size());
@@ -217,15 +175,113 @@
MixedTyped filtered_test = filter(test, is_ignored);
// We want "close-enough" results for float
- compare(filtered_golden, filtered_test);
+ compare(filtered_golden, filtered_test, fpRange);
}
}
+void Execute(sp<V1_0::IDevice>& device, std::function<V1_0::Model(void)> create_model,
+ std::function<bool(int)> is_ignored,
+ const std::vector<MixedTypedExampleType>& examples) {
+ V1_0::Model model = create_model();
+
+ // see if service can handle model
+ bool fullySupportsModel = false;
+ ErrorStatus supportedStatus;
+ sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+ ASSERT_NE(nullptr, preparedModelCallback.get());
+
+ Return<void> supportedCall = device->getSupportedOperations(
+ model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
+ supportedStatus = status;
+ ASSERT_NE(0ul, supported.size());
+ fullySupportsModel =
+ std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
+ });
+ ASSERT_TRUE(supportedCall.isOk());
+ ASSERT_EQ(ErrorStatus::NONE, supportedStatus);
+ Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
+ ASSERT_TRUE(prepareLaunchStatus.isOk());
+
+ // retrieve prepared model
+ preparedModelCallback->wait();
+ ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+ sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
+ if (fullySupportsModel) {
+ EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
+ } else {
+ EXPECT_TRUE(prepareReturnStatus == ErrorStatus::NONE ||
+ prepareReturnStatus == ErrorStatus::GENERAL_FAILURE);
+ }
+
+ // early termination if vendor service cannot fully prepare model
+ if (!fullySupportsModel && prepareReturnStatus == ErrorStatus::GENERAL_FAILURE) {
+ ASSERT_EQ(nullptr, preparedModel.get());
+ LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+ "prepare model that it does not support.";
+ std::cout << "[ ] Early termination of test because vendor service cannot "
+ "prepare model that it does not support."
+ << std::endl;
+ return;
+ }
+ ASSERT_NE(nullptr, preparedModel.get());
+
+ EvaluatePreparedModel(preparedModel, is_ignored, examples);
+}
+
+void Execute(sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model,
+ std::function<bool(int)> is_ignored,
+ const std::vector<MixedTypedExampleType>& examples) {
+ V1_1::Model model = create_model();
+
+ // see if service can handle model
+ bool fullySupportsModel = false;
+ ErrorStatus supportedStatus;
+ sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+ ASSERT_NE(nullptr, preparedModelCallback.get());
+
+ Return<void> supportedCall = device->getSupportedOperations_1_1(
+ model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
+ supportedStatus = status;
+ ASSERT_NE(0ul, supported.size());
+ fullySupportsModel =
+ std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
+ });
+ ASSERT_TRUE(supportedCall.isOk());
+ ASSERT_EQ(ErrorStatus::NONE, supportedStatus);
+ Return<ErrorStatus> prepareLaunchStatus =
+ device->prepareModel_1_1(model, preparedModelCallback);
+ ASSERT_TRUE(prepareLaunchStatus.isOk());
+
+ // retrieve prepared model
+ preparedModelCallback->wait();
+ ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+ sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
+ if (fullySupportsModel) {
+ EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
+ } else {
+ EXPECT_TRUE(prepareReturnStatus == ErrorStatus::NONE ||
+ prepareReturnStatus == ErrorStatus::GENERAL_FAILURE);
+ }
+
+ // early termination if vendor service cannot fully prepare model
+ if (!fullySupportsModel && prepareReturnStatus == ErrorStatus::GENERAL_FAILURE) {
+ ASSERT_EQ(nullptr, preparedModel.get());
+ LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+ "prepare model that it does not support.";
+ std::cout << "[ ] Early termination of test because vendor service cannot "
+ "prepare model that it does not support."
+ << std::endl;
+ return;
+ }
+ ASSERT_NE(nullptr, preparedModel.get());
+
+ // If in relaxed mode, set the error range to be 5ULP of FP16.
+ float fpRange = !model.relaxComputationFloat32toFloat16 ? 1e-5f : 5.0f * 0.0009765625f;
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, fpRange);
+}
+
} // namespace generated_tests
-} // namespace functional
-} // namespace vts
-} // namespace V1_0
} // namespace neuralnetworks
} // namespace hardware
} // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/Models.cpp b/neuralnetworks/1.0/vts/functional/Models.cpp
index 8ce4f25..180286a 100644
--- a/neuralnetworks/1.0/vts/functional/Models.cpp
+++ b/neuralnetworks/1.0/vts/functional/Models.cpp
@@ -17,19 +17,22 @@
#define LOG_TAG "neuralnetworks_hidl_hal_test"
#include "Models.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
#include <vector>
+using ::android::sp;
+
namespace android {
namespace hardware {
namespace neuralnetworks {
-namespace V1_0 {
-namespace vts {
-namespace functional {
// create a valid model
-Model createValidTestModel() {
+V1_1::Model createValidTestModel_1_1() {
const std::vector<float> operand2Data = {5.0f, 6.0f, 7.0f, 8.0f};
const uint32_t size = operand2Data.size() * sizeof(float);
@@ -103,39 +106,34 @@
}
// create first invalid model
-Model createInvalidTestModel1() {
- Model model = createValidTestModel();
+V1_1::Model createInvalidTestModel1_1_1() {
+ Model model = createValidTestModel_1_1();
model.operations[0].type = static_cast<OperationType>(0xDEADBEEF); /* INVALID */
return model;
}
// create second invalid model
-Model createInvalidTestModel2() {
- Model model = createValidTestModel();
+V1_1::Model createInvalidTestModel2_1_1() {
+ Model model = createValidTestModel_1_1();
const uint32_t operand1 = 0;
const uint32_t operand5 = 4; // INVALID OPERAND
model.inputIndexes = std::vector<uint32_t>({operand1, operand5 /* INVALID OPERAND */});
return model;
}
-// allocator helper
-hidl_memory allocateSharedMemory(int64_t size, const std::string& type = "ashmem") {
- hidl_memory memory;
+V1_0::Model createValidTestModel_1_0() {
+ V1_1::Model model = createValidTestModel_1_1();
+ return nn::convertToV1_0(model);
+}
- sp<IAllocator> allocator = IAllocator::getService(type);
- if (!allocator.get()) {
- return {};
- }
+V1_0::Model createInvalidTestModel1_1_0() {
+ V1_1::Model model = createInvalidTestModel1_1_1();
+ return nn::convertToV1_0(model);
+}
- Return<void> ret = allocator->allocate(size, [&](bool success, const hidl_memory& mem) {
- ASSERT_TRUE(success);
- memory = mem;
- });
- if (!ret.isOk()) {
- return {};
- }
-
- return memory;
+V1_0::Model createInvalidTestModel2_1_0() {
+ V1_1::Model model = createInvalidTestModel2_1_1();
+ return nn::convertToV1_0(model);
}
// create a valid request
@@ -154,8 +152,8 @@
std::vector<RequestArgument> outputs = {{
.location = {.poolIndex = OUTPUT, .offset = 0, .length = outputSize}, .dimensions = {},
}};
- std::vector<hidl_memory> pools = {allocateSharedMemory(inputSize),
- allocateSharedMemory(outputSize)};
+ std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
+ nn::allocateSharedMemory(outputSize)};
if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) {
return {};
}
@@ -199,9 +197,6 @@
return request;
}
-} // namespace functional
-} // namespace vts
-} // namespace V1_0
} // namespace neuralnetworks
} // namespace hardware
} // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/Models.h b/neuralnetworks/1.0/vts/functional/Models.h
index e0d57d5..9398235 100644
--- a/neuralnetworks/1.0/vts/functional/Models.h
+++ b/neuralnetworks/1.0/vts/functional/Models.h
@@ -16,28 +16,27 @@
#define LOG_TAG "neuralnetworks_hidl_hal_test"
-#include "VtsHalNeuralnetworksV1_0TargetTest.h"
+#include <android/hardware/neuralnetworks/1.1/types.h>
namespace android {
namespace hardware {
namespace neuralnetworks {
-namespace V1_0 {
-namespace vts {
-namespace functional {
-// create the model
-Model createValidTestModel();
-Model createInvalidTestModel1();
-Model createInvalidTestModel2();
+// create V1_1 model
+V1_1::Model createValidTestModel_1_1();
+V1_1::Model createInvalidTestModel1_1_1();
+V1_1::Model createInvalidTestModel2_1_1();
+
+// create V1_0 model
+V1_0::Model createValidTestModel_1_0();
+V1_0::Model createInvalidTestModel1_1_0();
+V1_0::Model createInvalidTestModel2_1_0();
// create the request
-Request createValidTestRequest();
-Request createInvalidTestRequest1();
-Request createInvalidTestRequest2();
+V1_0::Request createValidTestRequest();
+V1_0::Request createInvalidTestRequest1();
+V1_0::Request createInvalidTestRequest2();
-} // namespace functional
-} // namespace vts
-} // namespace V1_0
} // namespace neuralnetworks
} // namespace hardware
} // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.cpp
new file mode 100644
index 0000000..b14fb2c
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworksV1_0.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+
+using ::android::hardware::hidl_memory;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::sp;
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_0 {
+namespace vts {
+namespace functional {
+
+// allocator helper
+hidl_memory allocateSharedMemory(int64_t size) {
+ return nn::allocateSharedMemory(size);
+}
+
+// A class for test environment setup
+NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {}
+
+NeuralnetworksHidlEnvironment::~NeuralnetworksHidlEnvironment() {}
+
+NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() {
+ // This has to return a "new" object because it is freed inside
+ // ::testing::AddGlobalTestEnvironment when the gtest is being torn down
+ static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment();
+ return instance;
+}
+
+void NeuralnetworksHidlEnvironment::registerTestServices() {
+ registerTestService<V1_0::IDevice>();
+}
+
+// The main test class for NEURALNETWORK HIDL HAL.
+NeuralnetworksHidlTest::~NeuralnetworksHidlTest() {}
+
+void NeuralnetworksHidlTest::SetUp() {
+ device = ::testing::VtsHalHidlTargetTestBase::getService<V1_0::IDevice>(
+ NeuralnetworksHidlEnvironment::getInstance());
+ ASSERT_NE(nullptr, device.get());
+}
+
+void NeuralnetworksHidlTest::TearDown() {}
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_0
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.h b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.h
similarity index 69%
rename from neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.h
rename to neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.h
index 5cd209a..fbb1607 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.h
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -29,23 +29,6 @@
#include <gtest/gtest.h>
#include <string>
-using ::android::hardware::neuralnetworks::V1_0::IDevice;
-using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
-using ::android::hardware::neuralnetworks::V1_0::Capabilities;
-using ::android::hardware::neuralnetworks::V1_0::DeviceStatus;
-using ::android::hardware::neuralnetworks::V1_0::FusedActivationFunc;
-using ::android::hardware::neuralnetworks::V1_0::Model;
-using ::android::hardware::neuralnetworks::V1_0::OperationType;
-using ::android::hardware::neuralnetworks::V1_0::PerformanceInfo;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
-
namespace android {
namespace hardware {
namespace neuralnetworks {
@@ -53,6 +36,8 @@
namespace vts {
namespace functional {
+hidl_memory allocateSharedMemory(int64_t size);
+
// A class for test environment setup
class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
NeuralnetworksHidlEnvironment();
@@ -74,25 +59,22 @@
void SetUp() override;
void TearDown() override;
- sp<IPreparedModel> doPrepareModelShortcut();
-
- sp<IDevice> device;
+ sp<V1_0::IDevice> device;
};
-
} // namespace functional
} // namespace vts
// pretty-print values for error messages
-template<typename CharT, typename Traits>
+template <typename CharT, typename Traits>
::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& os,
- ErrorStatus errorStatus) {
+ V1_0::ErrorStatus errorStatus) {
return os << toString(errorStatus);
}
-template<typename CharT, typename Traits>
+template <typename CharT, typename Traits>
::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& os,
- DeviceStatus deviceStatus) {
+ V1_0::DeviceStatus deviceStatus) {
return os << toString(deviceStatus);
}
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0BasicTest.cpp
similarity index 80%
rename from neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.cpp
rename to neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0BasicTest.cpp
index b99e20e..e838997 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.cpp
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0BasicTest.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -16,7 +16,7 @@
#define LOG_TAG "neuralnetworks_hidl_hal_test"
-#include "VtsHalNeuralnetworksV1_0TargetTest.h"
+#include "VtsHalNeuralnetworksV1_0.h"
#include "Callbacks.h"
#include "Models.h"
@@ -26,51 +26,34 @@
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
+using ::android::hardware::neuralnetworks::V1_0::IDevice;
+using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
+using ::android::hardware::neuralnetworks::V1_0::Capabilities;
+using ::android::hardware::neuralnetworks::V1_0::DeviceStatus;
+using ::android::hardware::neuralnetworks::V1_0::FusedActivationFunc;
+using ::android::hardware::neuralnetworks::V1_0::Model;
+using ::android::hardware::neuralnetworks::V1_0::OperationType;
+using ::android::hardware::neuralnetworks::V1_0::PerformanceInfo;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::sp;
+
namespace android {
namespace hardware {
namespace neuralnetworks {
namespace V1_0 {
namespace vts {
namespace functional {
-
using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
-using ::generated_tests::MixedTypedExampleType;
-namespace generated_tests {
-extern void Execute(const sp<IDevice>&, std::function<Model(void)>, std::function<bool(int)>,
- const std::vector<MixedTypedExampleType>&);
-}
-
-// A class for test environment setup
-NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {}
-
-NeuralnetworksHidlEnvironment::~NeuralnetworksHidlEnvironment() {}
-
-NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() {
- // This has to return a "new" object because it is freed inside
- // ::testing::AddGlobalTestEnvironment when the gtest is being torn down
- static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment();
- return instance;
-}
-
-void NeuralnetworksHidlEnvironment::registerTestServices() {
- registerTestService<IDevice>();
-}
-
-// The main test class for NEURALNETWORK HIDL HAL.
-NeuralnetworksHidlTest::~NeuralnetworksHidlTest() {}
-
-void NeuralnetworksHidlTest::SetUp() {
- device = ::testing::VtsHalHidlTargetTestBase::getService<IDevice>(
- NeuralnetworksHidlEnvironment::getInstance());
- ASSERT_NE(nullptr, device.get());
-}
-
-void NeuralnetworksHidlTest::TearDown() {}
-
-sp<IPreparedModel> NeuralnetworksHidlTest::doPrepareModelShortcut() {
- Model model = createValidTestModel();
+inline sp<IPreparedModel> doPrepareModelShortcut(sp<IDevice>& device) {
+ Model model = createValidTestModel_1_0();
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
if (preparedModelCallback == nullptr) {
@@ -116,7 +99,7 @@
// supported operations positive test
TEST_F(NeuralnetworksHidlTest, SupportedOperationsPositiveTest) {
- Model model = createValidTestModel();
+ Model model = createValidTestModel_1_0();
Return<void> ret = device->getSupportedOperations(
model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
EXPECT_EQ(ErrorStatus::NONE, status);
@@ -127,7 +110,7 @@
// supported operations negative test 1
TEST_F(NeuralnetworksHidlTest, SupportedOperationsNegativeTest1) {
- Model model = createInvalidTestModel1();
+ Model model = createInvalidTestModel1_1_0();
Return<void> ret = device->getSupportedOperations(
model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
@@ -138,7 +121,7 @@
// supported operations negative test 2
TEST_F(NeuralnetworksHidlTest, SupportedOperationsNegativeTest2) {
- Model model = createInvalidTestModel2();
+ Model model = createInvalidTestModel2_1_0();
Return<void> ret = device->getSupportedOperations(
model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
@@ -149,7 +132,7 @@
// prepare simple model positive test
TEST_F(NeuralnetworksHidlTest, SimplePrepareModelPositiveTest) {
- Model model = createValidTestModel();
+ Model model = createValidTestModel_1_0();
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
ASSERT_NE(nullptr, preparedModelCallback.get());
Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
@@ -165,7 +148,7 @@
// prepare simple model negative test 1
TEST_F(NeuralnetworksHidlTest, SimplePrepareModelNegativeTest1) {
- Model model = createInvalidTestModel1();
+ Model model = createInvalidTestModel1_1_0();
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
ASSERT_NE(nullptr, preparedModelCallback.get());
Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
@@ -181,7 +164,7 @@
// prepare simple model negative test 2
TEST_F(NeuralnetworksHidlTest, SimplePrepareModelNegativeTest2) {
- Model model = createInvalidTestModel2();
+ Model model = createInvalidTestModel2_1_0();
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
ASSERT_NE(nullptr, preparedModelCallback.get());
Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
@@ -201,7 +184,7 @@
std::vector<float> expectedData = {6.0f, 8.0f, 10.0f, 12.0f};
const uint32_t OUTPUT = 1;
- sp<IPreparedModel> preparedModel = doPrepareModelShortcut();
+ sp<IPreparedModel> preparedModel = doPrepareModelShortcut(device);
ASSERT_NE(nullptr, preparedModel.get());
Request request = createValidTestRequest();
@@ -235,7 +218,7 @@
// execute simple graph negative test 1
TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphNegativeTest1) {
- sp<IPreparedModel> preparedModel = doPrepareModelShortcut();
+ sp<IPreparedModel> preparedModel = doPrepareModelShortcut(device);
ASSERT_NE(nullptr, preparedModel.get());
Request request = createInvalidTestRequest1();
@@ -252,7 +235,7 @@
// execute simple graph negative test 2
TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphNegativeTest2) {
- sp<IPreparedModel> preparedModel = doPrepareModelShortcut();
+ sp<IPreparedModel> preparedModel = doPrepareModelShortcut(device);
ASSERT_NE(nullptr, preparedModel.get());
Request request = createInvalidTestRequest2();
@@ -267,16 +250,6 @@
EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
}
-// Mixed-typed examples
-typedef MixedTypedExampleType MixedTypedExample;
-
-// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_vts_tests.cpp"
-
-// TODO: Add tests for execution failure, or wait_for/wait_until timeout.
-// Discussion:
-// https://googleplex-android-review.git.corp.google.com/#/c/platform/hardware/interfaces/+/2654636/5/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.cpp@222
-
} // namespace functional
} // namespace vts
} // namespace V1_0
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0GeneratedTest.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0GeneratedTest.cpp
new file mode 100644
index 0000000..b99aef7
--- /dev/null
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0GeneratedTest.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworksV1_0.h"
+
+#include "Callbacks.h"
+#include "TestHarness.h"
+
+#include <android-base/logging.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+using ::android::hardware::neuralnetworks::V1_0::IDevice;
+using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
+using ::android::hardware::neuralnetworks::V1_0::Capabilities;
+using ::android::hardware::neuralnetworks::V1_0::DeviceStatus;
+using ::android::hardware::neuralnetworks::V1_0::FusedActivationFunc;
+using ::android::hardware::neuralnetworks::V1_0::Model;
+using ::android::hardware::neuralnetworks::V1_0::OperationType;
+using ::android::hardware::neuralnetworks::V1_0::PerformanceInfo;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::sp;
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+
+namespace generated_tests {
+using ::generated_tests::MixedTypedExampleType;
+extern void Execute(sp<IDevice>&, std::function<Model(void)>, std::function<bool(int)>,
+ const std::vector<MixedTypedExampleType>&);
+} // namespace generated_tests
+
+namespace V1_0 {
+namespace vts {
+namespace functional {
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+
+// Mixed-typed examples
+typedef generated_tests::MixedTypedExampleType MixedTypedExample;
+
+// in frameworks/ml/nn/runtime/tests/generated/
+#include "all_generated_V1_0_vts_tests.cpp"
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_0
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.1/types.hal b/neuralnetworks/1.1/types.hal
index 18863d3..fae5dd0 100644
--- a/neuralnetworks/1.1/types.hal
+++ b/neuralnetworks/1.1/types.hal
@@ -330,4 +330,12 @@
* equals OperandLifeTime::CONSTANT_REFERENCE.
*/
vec<memory> pools;
+
+ /**
+ * 'true' indicates TENSOR_FLOAT32 may be calculated with range and/or
+ * precision as low as that of the IEEE 754 16-bit floating-point format.
+ * 'false' indicates TENSOR_FLOAT32 must be calculated using at least the
+ * range and precision of the IEEE 754 32-bit floating-point format.
+ */
+ bool relaxComputationFloat32toFloat16;
};
diff --git a/neuralnetworks/1.1/vts/OWNERS b/neuralnetworks/1.1/vts/OWNERS
new file mode 100644
index 0000000..7f75ab3
--- /dev/null
+++ b/neuralnetworks/1.1/vts/OWNERS
@@ -0,0 +1,10 @@
+# Neuralnetworks team
+butlermichael@google.com
+dgross@google.com
+jeanluc@google.com
+miaowang@google.com
+yangni@google.com
+
+# VTS team
+yim@google.com
+yuexima@google.com
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..623b441
--- /dev/null
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2018 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.
+//
+
+cc_test {
+ name: "VtsHalNeuralnetworksV1_1TargetTest",
+ srcs: [
+ "VtsHalNeuralnetworksV1_1.cpp",
+ "VtsHalNeuralnetworksV1_1BasicTest.cpp",
+ "VtsHalNeuralnetworksV1_1GeneratedTest.cpp",
+ ],
+ defaults: ["VtsHalTargetTestDefaults"],
+ static_libs: [
+ "android.hardware.neuralnetworks@1.0",
+ "android.hardware.neuralnetworks@1.1",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libhidlmemory",
+ "libneuralnetworks_utils",
+ "VtsHalNeuralnetworksTest_utils",
+ ],
+ header_libs: [
+ "libneuralnetworks_headers",
+ "libneuralnetworks_generated_test_harness_headers",
+ "libneuralnetworks_generated_tests",
+ ],
+}
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.cpp
new file mode 100644
index 0000000..b1d3be7
--- /dev/null
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworksV1_1.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <hidlmemory/mapping.h>
+
+using ::android::hardware::hidl_memory;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::sp;
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_1 {
+namespace vts {
+namespace functional {
+
+// allocator helper
+hidl_memory allocateSharedMemory(int64_t size) {
+ return nn::allocateSharedMemory(size);
+}
+
+// A class for test environment setup
+NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {}
+
+NeuralnetworksHidlEnvironment::~NeuralnetworksHidlEnvironment() {}
+
+NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() {
+ // This has to return a "new" object because it is freed inside
+ // ::testing::AddGlobalTestEnvironment when the gtest is being torn down
+ static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment();
+ return instance;
+}
+
+void NeuralnetworksHidlEnvironment::registerTestServices() {
+ registerTestService<V1_1::IDevice>();
+}
+
+// The main test class for NEURALNETWORK HIDL HAL.
+NeuralnetworksHidlTest::~NeuralnetworksHidlTest() {}
+
+void NeuralnetworksHidlTest::SetUp() {
+ device = ::testing::VtsHalHidlTargetTestBase::getService<V1_1::IDevice>(
+ NeuralnetworksHidlEnvironment::getInstance());
+ ASSERT_NE(nullptr, device.get());
+}
+
+void NeuralnetworksHidlTest::TearDown() {}
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_1
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.h
similarity index 61%
copy from neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.h
copy to neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.h
index 5cd209a..426246c 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.h
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#ifndef VTS_HAL_NEURALNETWORKS_V1_0_TARGET_TESTS_H
-#define VTS_HAL_NEURALNETWORKS_V1_0_TARGET_TESTS_H
+#ifndef VTS_HAL_NEURALNETWORKS_V1_1_H
+#define VTS_HAL_NEURALNETWORKS_V1_1_H
-#include <android/hardware/neuralnetworks/1.0/IDevice.h>
#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
-#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/IDevice.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
#include <VtsHalHidlTargetTestBase.h>
@@ -29,29 +29,13 @@
#include <gtest/gtest.h>
#include <string>
-using ::android::hardware::neuralnetworks::V1_0::IDevice;
-using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
-using ::android::hardware::neuralnetworks::V1_0::Capabilities;
-using ::android::hardware::neuralnetworks::V1_0::DeviceStatus;
-using ::android::hardware::neuralnetworks::V1_0::FusedActivationFunc;
-using ::android::hardware::neuralnetworks::V1_0::Model;
-using ::android::hardware::neuralnetworks::V1_0::OperationType;
-using ::android::hardware::neuralnetworks::V1_0::PerformanceInfo;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
-
namespace android {
namespace hardware {
namespace neuralnetworks {
-namespace V1_0 {
+namespace V1_1 {
namespace vts {
namespace functional {
+hidl_memory allocateSharedMemory(int64_t size);
// A class for test environment setup
class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
@@ -74,31 +58,28 @@
void SetUp() override;
void TearDown() override;
- sp<IPreparedModel> doPrepareModelShortcut();
-
- sp<IDevice> device;
+ sp<V1_1::IDevice> device;
};
-
} // namespace functional
} // namespace vts
// pretty-print values for error messages
-template<typename CharT, typename Traits>
+template <typename CharT, typename Traits>
::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& os,
- ErrorStatus errorStatus) {
+ V1_0::ErrorStatus errorStatus) {
return os << toString(errorStatus);
}
-template<typename CharT, typename Traits>
+template <typename CharT, typename Traits>
::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& os,
- DeviceStatus deviceStatus) {
+ V1_0::DeviceStatus deviceStatus) {
return os << toString(deviceStatus);
}
-} // namespace V1_0
+} // namespace V1_1
} // namespace neuralnetworks
} // namespace hardware
} // namespace android
-#endif // VTS_HAL_NEURALNETWORKS_V1_0_TARGET_TESTS_H
+#endif // VTS_HAL_NEURALNETWORKS_V1_1_H
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1BasicTest.cpp
similarity index 74%
copy from neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.cpp
copy to neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1BasicTest.cpp
index b99e20e..51eff2a 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.cpp
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1BasicTest.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -16,67 +16,58 @@
#define LOG_TAG "neuralnetworks_hidl_hal_test"
-#include "VtsHalNeuralnetworksV1_0TargetTest.h"
+#include "VtsHalNeuralnetworksV1_1.h"
#include "Callbacks.h"
#include "Models.h"
#include "TestHarness.h"
#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.1/IDevice.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
+using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
+using ::android::hardware::neuralnetworks::V1_0::Capabilities;
+using ::android::hardware::neuralnetworks::V1_0::DeviceStatus;
+using ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
+using ::android::hardware::neuralnetworks::V1_0::FusedActivationFunc;
+using ::android::hardware::neuralnetworks::V1_0::Operand;
+using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
+using ::android::hardware::neuralnetworks::V1_0::OperandType;
+using ::android::hardware::neuralnetworks::V1_0::Request;
+using ::android::hardware::neuralnetworks::V1_1::IDevice;
+using ::android::hardware::neuralnetworks::V1_1::Model;
+using ::android::hardware::neuralnetworks::V1_1::Operation;
+using ::android::hardware::neuralnetworks::V1_1::OperationType;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::sp;
+
namespace android {
namespace hardware {
namespace neuralnetworks {
-namespace V1_0 {
+namespace V1_1 {
namespace vts {
namespace functional {
-
using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
-using ::generated_tests::MixedTypedExampleType;
-namespace generated_tests {
-extern void Execute(const sp<IDevice>&, std::function<Model(void)>, std::function<bool(int)>,
- const std::vector<MixedTypedExampleType>&);
-}
-
-// A class for test environment setup
-NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {}
-
-NeuralnetworksHidlEnvironment::~NeuralnetworksHidlEnvironment() {}
-
-NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() {
- // This has to return a "new" object because it is freed inside
- // ::testing::AddGlobalTestEnvironment when the gtest is being torn down
- static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment();
- return instance;
-}
-
-void NeuralnetworksHidlEnvironment::registerTestServices() {
- registerTestService<IDevice>();
-}
-
-// The main test class for NEURALNETWORK HIDL HAL.
-NeuralnetworksHidlTest::~NeuralnetworksHidlTest() {}
-
-void NeuralnetworksHidlTest::SetUp() {
- device = ::testing::VtsHalHidlTargetTestBase::getService<IDevice>(
- NeuralnetworksHidlEnvironment::getInstance());
- ASSERT_NE(nullptr, device.get());
-}
-
-void NeuralnetworksHidlTest::TearDown() {}
-
-sp<IPreparedModel> NeuralnetworksHidlTest::doPrepareModelShortcut() {
- Model model = createValidTestModel();
+inline sp<IPreparedModel> doPrepareModelShortcut(sp<IDevice>& device) {
+ Model model = createValidTestModel_1_1();
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
if (preparedModelCallback == nullptr) {
return nullptr;
}
- Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
+ Return<ErrorStatus> prepareLaunchStatus =
+ device->prepareModel_1_1(model, preparedModelCallback);
if (!prepareLaunchStatus.isOk() || prepareLaunchStatus != ErrorStatus::NONE) {
return nullptr;
}
@@ -116,8 +107,8 @@
// supported operations positive test
TEST_F(NeuralnetworksHidlTest, SupportedOperationsPositiveTest) {
- Model model = createValidTestModel();
- Return<void> ret = device->getSupportedOperations(
+ Model model = createValidTestModel_1_1();
+ Return<void> ret = device->getSupportedOperations_1_1(
model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
EXPECT_EQ(ErrorStatus::NONE, status);
EXPECT_EQ(model.operations.size(), supported.size());
@@ -127,8 +118,8 @@
// supported operations negative test 1
TEST_F(NeuralnetworksHidlTest, SupportedOperationsNegativeTest1) {
- Model model = createInvalidTestModel1();
- Return<void> ret = device->getSupportedOperations(
+ Model model = createInvalidTestModel1_1_1();
+ Return<void> ret = device->getSupportedOperations_1_1(
model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
(void)supported;
@@ -138,8 +129,8 @@
// supported operations negative test 2
TEST_F(NeuralnetworksHidlTest, SupportedOperationsNegativeTest2) {
- Model model = createInvalidTestModel2();
- Return<void> ret = device->getSupportedOperations(
+ Model model = createInvalidTestModel2_1_1();
+ Return<void> ret = device->getSupportedOperations_1_1(
model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
(void)supported;
@@ -149,10 +140,11 @@
// prepare simple model positive test
TEST_F(NeuralnetworksHidlTest, SimplePrepareModelPositiveTest) {
- Model model = createValidTestModel();
+ Model model = createValidTestModel_1_1();
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
ASSERT_NE(nullptr, preparedModelCallback.get());
- Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
+ Return<ErrorStatus> prepareLaunchStatus =
+ device->prepareModel_1_1(model, preparedModelCallback);
ASSERT_TRUE(prepareLaunchStatus.isOk());
EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
@@ -165,10 +157,11 @@
// prepare simple model negative test 1
TEST_F(NeuralnetworksHidlTest, SimplePrepareModelNegativeTest1) {
- Model model = createInvalidTestModel1();
+ Model model = createInvalidTestModel1_1_1();
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
ASSERT_NE(nullptr, preparedModelCallback.get());
- Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
+ Return<ErrorStatus> prepareLaunchStatus =
+ device->prepareModel_1_1(model, preparedModelCallback);
ASSERT_TRUE(prepareLaunchStatus.isOk());
EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
@@ -181,10 +174,11 @@
// prepare simple model negative test 2
TEST_F(NeuralnetworksHidlTest, SimplePrepareModelNegativeTest2) {
- Model model = createInvalidTestModel2();
+ Model model = createInvalidTestModel2_1_1();
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
ASSERT_NE(nullptr, preparedModelCallback.get());
- Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
+ Return<ErrorStatus> prepareLaunchStatus =
+ device->prepareModel_1_1(model, preparedModelCallback);
ASSERT_TRUE(prepareLaunchStatus.isOk());
EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
@@ -201,7 +195,7 @@
std::vector<float> expectedData = {6.0f, 8.0f, 10.0f, 12.0f};
const uint32_t OUTPUT = 1;
- sp<IPreparedModel> preparedModel = doPrepareModelShortcut();
+ sp<IPreparedModel> preparedModel = doPrepareModelShortcut(device);
ASSERT_NE(nullptr, preparedModel.get());
Request request = createValidTestRequest();
@@ -235,7 +229,7 @@
// execute simple graph negative test 1
TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphNegativeTest1) {
- sp<IPreparedModel> preparedModel = doPrepareModelShortcut();
+ sp<IPreparedModel> preparedModel = doPrepareModelShortcut(device);
ASSERT_NE(nullptr, preparedModel.get());
Request request = createInvalidTestRequest1();
@@ -252,7 +246,7 @@
// execute simple graph negative test 2
TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphNegativeTest2) {
- sp<IPreparedModel> preparedModel = doPrepareModelShortcut();
+ sp<IPreparedModel> preparedModel = doPrepareModelShortcut(device);
ASSERT_NE(nullptr, preparedModel.get());
Request request = createInvalidTestRequest2();
@@ -267,24 +261,14 @@
EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
}
-// Mixed-typed examples
-typedef MixedTypedExampleType MixedTypedExample;
-
-// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_vts_tests.cpp"
-
-// TODO: Add tests for execution failure, or wait_for/wait_until timeout.
-// Discussion:
-// https://googleplex-android-review.git.corp.google.com/#/c/platform/hardware/interfaces/+/2654636/5/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0TargetTest.cpp@222
-
} // namespace functional
} // namespace vts
-} // namespace V1_0
+} // namespace V1_1
} // namespace neuralnetworks
} // namespace hardware
} // namespace android
-using android::hardware::neuralnetworks::V1_0::vts::functional::NeuralnetworksHidlEnvironment;
+using android::hardware::neuralnetworks::V1_1::vts::functional::NeuralnetworksHidlEnvironment;
int main(int argc, char** argv) {
::testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance());
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1GeneratedTest.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1GeneratedTest.cpp
new file mode 100644
index 0000000..025d9fe
--- /dev/null
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1GeneratedTest.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworksV1_1.h"
+
+#include "Callbacks.h"
+#include "TestHarness.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.1/IDevice.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
+using ::android::hardware::neuralnetworks::V1_0::Capabilities;
+using ::android::hardware::neuralnetworks::V1_0::DeviceStatus;
+using ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
+using ::android::hardware::neuralnetworks::V1_0::FusedActivationFunc;
+using ::android::hardware::neuralnetworks::V1_0::Operand;
+using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
+using ::android::hardware::neuralnetworks::V1_0::OperandType;
+using ::android::hardware::neuralnetworks::V1_0::Request;
+using ::android::hardware::neuralnetworks::V1_1::IDevice;
+using ::android::hardware::neuralnetworks::V1_1::Model;
+using ::android::hardware::neuralnetworks::V1_1::Operation;
+using ::android::hardware::neuralnetworks::V1_1::OperationType;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::sp;
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+
+namespace generated_tests {
+using ::generated_tests::MixedTypedExampleType;
+extern void Execute(sp<V1_1::IDevice>&, std::function<Model(void)>, std::function<bool(int)>,
+ const std::vector<MixedTypedExampleType>&);
+} // namespace generated_tests
+
+namespace V1_1 {
+namespace vts {
+namespace functional {
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+
+// Mixed-typed examples
+typedef generated_tests::MixedTypedExampleType MixedTypedExample;
+
+// in frameworks/ml/nn/runtime/tests/generated/
+#include "all_generated_V1_0_vts_tests.cpp"
+#include "all_generated_V1_1_vts_tests.cpp"
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_1
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp b/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
index 2f00fbb..e17c961 100644
--- a/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
+++ b/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
@@ -24,6 +24,7 @@
#include <VtsHalHidlTargetCallbackBase.h>
#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
using ::android::hardware::nfc::V1_0::INfc;
using ::android::hardware::nfc::V1_0::INfcClientCallback;
@@ -93,11 +94,26 @@
};
};
+// Test environment for Nfc HIDL HAL.
+class NfcHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static NfcHidlEnvironment* Instance() {
+ static NfcHidlEnvironment* instance = new NfcHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<INfc>(); }
+ private:
+ NfcHidlEnvironment() {}
+};
+
// The main test class for NFC HIDL HAL.
class NfcHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
virtual void SetUp() override {
- nfc_ = ::testing::VtsHalHidlTargetTestBase::getService<INfc>();
+ nfc_ = ::testing::VtsHalHidlTargetTestBase::getService<INfc>(
+ NfcHidlEnvironment::Instance()->getServiceName<INfc>());
ASSERT_NE(nfc_, nullptr);
nfc_cb_ = new NfcClientCallback();
@@ -163,15 +179,6 @@
sp<NfcClientCallback> nfc_cb_;
};
-// A class for test environment setup (kept since this file is a template).
-class NfcHidlEnvironment : public ::testing::Environment {
- public:
- virtual void SetUp() {}
- virtual void TearDown() {}
-
- private:
-};
-
/*
* OpenAndClose:
* Makes an open call, waits for NfcEvent.OPEN_CPLT
@@ -586,8 +593,9 @@
}
int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(new NfcHidlEnvironment);
+ ::testing::AddGlobalTestEnvironment(NfcHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
+ NfcHidlEnvironment::Instance()->init(&argc, argv);
std::system("svc nfc disable"); /* Turn off NFC */
sleep(5);
diff --git a/nfc/1.1/vts/functional/VtsHalNfcV1_1TargetTest.cpp b/nfc/1.1/vts/functional/VtsHalNfcV1_1TargetTest.cpp
index a5b40d4..bef412b 100644
--- a/nfc/1.1/vts/functional/VtsHalNfcV1_1TargetTest.cpp
+++ b/nfc/1.1/vts/functional/VtsHalNfcV1_1TargetTest.cpp
@@ -25,6 +25,7 @@
#include <VtsHalHidlTargetCallbackBase.h>
#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
using ::android::hardware::nfc::V1_1::INfc;
using ::android::hardware::nfc::V1_1::INfcClientCallback;
@@ -78,6 +79,20 @@
};
};
+// Test environment for Nfc HIDL HAL.
+class NfcHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static NfcHidlEnvironment* Instance() {
+ static NfcHidlEnvironment* instance = new NfcHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<INfc>(); }
+ private:
+ NfcHidlEnvironment() {}
+};
+
// The main test class for NFC HIDL HAL.
class NfcHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
@@ -127,15 +142,6 @@
sp<NfcClientCallback> nfc_cb_;
};
-// A class for test environment setup (kept since this file is a template).
-class NfcHidlEnvironment : public ::testing::Environment {
- public:
- virtual void SetUp() {}
- virtual void TearDown() {}
-
- private:
-};
-
/*
* factoryReset
* calls factoryReset()
@@ -204,8 +210,9 @@
}
int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(new NfcHidlEnvironment);
+ ::testing::AddGlobalTestEnvironment(NfcHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
+ NfcHidlEnvironment::Instance()->init(&argc, argv);
std::system("svc nfc disable"); /* Turn off NFC */
sleep(5);
diff --git a/radio/1.0/types.hal b/radio/1.0/types.hal
index 4d22bc0..6787a82 100644
--- a/radio/1.0/types.hal
+++ b/radio/1.0/types.hal
@@ -1292,10 +1292,9 @@
// from cell to device.
// Approximate distance is calculated using
// 300m/us * timingAdvance.
- // Range: 0 to 0x7FFFFFFE
- // INT_MAX : 0x7FFFFFFF denotes invalid value.
- // Reference: 3GPP 36.321 section 6.1.3.5
- // also: http://www.cellular-planningoptimization.com/2010/02/timing-advance-with-calculation.html
+ // Range: 0 to 1282 inclusive.
+ // INT_MAX : 0x7FFFFFFF denotes unknown value.
+ // Reference: 3GPP 36.213 section 4.2.3
};
struct TdScdmaSignalStrength {
diff --git a/radio/1.2/Android.bp b/radio/1.2/Android.bp
index 48ac5a1..a9c80b7 100644
--- a/radio/1.2/Android.bp
+++ b/radio/1.2/Android.bp
@@ -28,11 +28,13 @@
"CellIdentityGsm",
"CellIdentityLte",
"CellIdentityOperatorNames",
+ "CellIdentityTdscdma",
"CellIdentityWcdma",
"CellInfo",
"CellInfoCdma",
"CellInfoGsm",
"CellInfoLte",
+ "CellInfoTdscdma",
"CellInfoWcdma",
"DataRequestReason",
"IncrementalResultsPeriodicityRange",
@@ -44,6 +46,9 @@
"PhysicalChannelConfig",
"RadioConst",
"ScanIntervalRange",
+ "SignalStrength",
+ "TdscdmaSignalStrength",
+ "WcdmaSignalStrength",
],
gen_java: true,
}
diff --git a/radio/1.2/IRadio.hal b/radio/1.2/IRadio.hal
index 67ce56c..6463b0f 100644
--- a/radio/1.2/IRadio.hal
+++ b/radio/1.2/IRadio.hal
@@ -50,7 +50,7 @@
*
* @param serial Serial number of request.
* @param indicationFilter 32-bit bitmap of IndicationFilter. Bits set to 1 indicate the
- * indications are enabled. See @1.2::IndicationFilter for the definition of each bit.
+ * indications are enabled. See @1.2::IndicationFilter for the definition of each bit.
*
* Response callback is IRadioResponse.setIndicationFilterResponse()
*/
@@ -68,16 +68,16 @@
*
* @param serial Serial number of request.
* @param hysteresisMs A hysteresis time in milliseconds to prevent flapping. A value of 0
- * disables hysteresis.
+ * disables hysteresis.
* @param hysteresisDb An interval in dB defining the required magnitude change between reports.
- * hysteresisDb must be smaller than the smallest threshold delta. An
- * interval value of 0 disables hysteresis.
+ * hysteresisDb must be smaller than the smallest threshold delta. An
+ * interval value of 0 disables hysteresis.
* @param thresholdsDbm A vector of trigger thresholds in dBm. A vector size of 0 disables the
- * use of thresholds for reporting.
- * @param ran The type of network for which to apply these thresholds.
+ * use of thresholds for reporting.
+ * @param accessNetwork The type of network for which to apply these thresholds.
*/
oneway setSignalStrengthReportingCriteria(int32_t serial, int32_t hysteresisMs,
- int32_t hysteresisDb, vec<int32_t> thresholdsDbm, RadioAccessNetworks ran);
+ int32_t hysteresisDb, vec<int32_t> thresholdsDbm, AccessNetwork accessNetwork);
/**
* Sets the link capacity reporting criteria.
@@ -91,23 +91,22 @@
*
* @param serial Serial number of request.
* @param hysteresisMs A hysteresis time in milliseconds to prevent flapping. A value of 0
- * disables hysteresis.
+ * disables hysteresis.
* @param hysteresisDlKbps An interval in kbps defining the required magnitude change between DL
- * reports. hysteresisDlKbps must be smaller than the smallest threshold
- * delta. A value of 0 disables hysteresis.
+ * reports. hysteresisDlKbps must be smaller than the smallest threshold delta. A value of 0
+ * disables hysteresis.
* @param hysteresisUlKbps An interval in kbps defining the required magnitude change between UL
- * reports. hysteresisUlKbps must be smaller than the smallest threshold
- * delta. A value of 0 disables hysteresis.
+ * reports. hysteresisUlKbps must be smaller than the smallest threshold delta. A value of 0
+ * disables hysteresis.
* @param thresholdsDownlinkKbps A vector of trigger thresholds in kbps for downlink reports. A
- * vector size of 0 disables the use of DL thresholds for
- * reporting.
+ * vector size of 0 disables the use of DL thresholds for reporting.
* @param thresholdsUplinkKbps A vector of trigger thresholds in kbps for uplink reports. A
- * vector size of 0 disables the use of UL thresholds for reporting.
- * @param ran The type of network for which to apply these thresholds.
+ * vector size of 0 disables the use of UL thresholds for reporting.
+ * @param accessNetwork The type of network for which to apply these thresholds.
*/
oneway setLinkCapacityReportingCriteria(int32_t serial, int32_t hysteresisMs,
int32_t hysteresisDlKbps, int32_t hysteresisUlKbps, vec<int32_t> thresholdsDownlinkKbps,
- vec<int32_t> thresholdsUplinkKbps, RadioAccessNetworks ran);
+ vec<int32_t> thresholdsUplinkKbps, AccessNetwork accessNetwork);
/**
* Setup a packet data connection. If DataCallResponse.status returns DataCallFailCause:NONE,
diff --git a/radio/1.2/IRadioIndication.hal b/radio/1.2/IRadioIndication.hal
index a124557..3d93b98 100644
--- a/radio/1.2/IRadioIndication.hal
+++ b/radio/1.2/IRadioIndication.hal
@@ -34,7 +34,7 @@
* Same information as returned by getCellInfoList() in 1.0::IRadio.
*
* @param type Type of radio indication
- * @param records Current cell information known to radio
+ * @param records Current cell information
*/
oneway cellInfoList_1_2(RadioIndicationType type, vec<CellInfo> records);
@@ -50,7 +50,7 @@
* suppressed by @1.2::IRadio.setIndicationFilter_1_2().
*
* @param type Type of radio indication
- * @param lce LinkCapacityEstimate information as defined in types.hal
+ * @param lce LinkCapacityEstimate
*/
oneway currentLinkCapacityEstimate(RadioIndicationType type, LinkCapacityEstimate lce);
@@ -58,8 +58,16 @@
* Indicates physical channel configurations.
*
* @param type Type of radio indication
- * @param configs List of PhysicalChannelConfigs as defined in types.hal
+ * @param configs Vector of PhysicalChannelConfigs
*/
oneway currentPhysicalChannelConfigs(RadioIndicationType type,
vec<PhysicalChannelConfig> configs);
+
+ /**
+ * Indicates current signal strength of the radio.
+ *
+ * @param type Type of radio indication
+ * @param signalStrength SignalStrength information
+ */
+ oneway currentSignalStrength_1_2(RadioIndicationType type, SignalStrength signalStrength);
};
diff --git a/radio/1.2/IRadioResponse.hal b/radio/1.2/IRadioResponse.hal
index 93ec4d7..f26c9ec 100644
--- a/radio/1.2/IRadioResponse.hal
+++ b/radio/1.2/IRadioResponse.hal
@@ -88,4 +88,14 @@
* RadioError:CANCELLED
*/
oneway getCurrentCallsResponse_1_2(RadioResponseInfo info, vec<Call> calls);
+
+ /**
+ * @param signalStrength Current signal strength
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ */
+ oneway getSignalStrengthResponse_1_2(RadioResponseInfo info, SignalStrength signalStrength);
};
diff --git a/radio/1.2/types.hal b/radio/1.2/types.hal
index c353645..b68895e 100644
--- a/radio/1.2/types.hal
+++ b/radio/1.2/types.hal
@@ -17,12 +17,13 @@
package android.hardware.radio@1.2;
import @1.0::Call;
-import @1.0::CdmaSignalStrength;
import @1.0::CardState;
import @1.0::CardStatus;
+import @1.0::CdmaSignalStrength;
import @1.0::CellIdentityCdma;
import @1.0::CellIdentityGsm;
import @1.0::CellIdentityLte;
+import @1.0::CellIdentityTdscdma;
import @1.0::CellIdentityWcdma;
import @1.0::CellInfoTdscdma;
import @1.0::CellInfoType;
@@ -30,10 +31,12 @@
import @1.0::GsmSignalStrength;
import @1.0::LteSignalStrength;
import @1.0::RadioConst;
+import @1.0::RadioError;
+import @1.0::SignalStrength;
+import @1.0::TdScdmaSignalStrength;
import @1.0::TimeStampType;
import @1.0::WcdmaSignalStrength;
import @1.1::RadioAccessSpecifier;
-import @1.0::RadioError;
import @1.1::ScanStatus;
import @1.1::ScanType;
@@ -251,6 +254,15 @@
int32_t bandwidth;
};
+struct CellIdentityTdscdma {
+ @1.0::CellIdentityTdscdma base;
+ /**
+ * 16-bit UMTS Absolute RF Channel Number defined in TS 25.102 5.4.4; this value must be valid.
+ */
+ int32_t uarfcn;
+ CellIdentityOperatorNames operatorNames;
+};
+
struct CellIdentityWcdma {
@1.0::CellIdentityWcdma base;
CellIdentityOperatorNames operatorNames;
@@ -277,6 +289,11 @@
LteSignalStrength signalStrengthLte;
};
+struct CellInfoTdscdma {
+ CellIdentityTdscdma cellIdentityTdscdma;
+ TdscdmaSignalStrength signalStrengthTdscdma;
+};
+
struct CellInfo {
/**
* Cell type for selecting from union CellInfo.
@@ -344,11 +361,17 @@
struct LinkCapacityEstimate {
/**
- * Estimated downlink capacity in kbps.
+ * Estimated downlink capacity in kbps. This bandwidth estimate shall be the estimated
+ * maximum sustainable link bandwidth (as would be measured at the Upper PDCP or SNDCP SAP).
+ * If the DL Aggregate Maximum Bit Rate is known, this value shall not exceed the DL-AMBR
+ * for the Internet PDN connection.
*/
uint32_t downlinkCapacityKbps;
/**
- * Estimated uplink capacity in kbps.
+ * Estimated uplink capacity in kbps. This bandwidth estimate shall be the estimated
+ * maximum sustainable link bandwidth (as would be measured at the Upper PDCP or SNDCP SAP).
+ * If the UL Aggregate Maximum Bit Rate is known, this value shall not exceed the UL-AMBR
+ * for the Internet PDN connection.
*/
uint32_t uplinkCapacityKbps;
};
@@ -397,3 +420,45 @@
@1.0::Call base;
AudioQuality audioQuality;
};
+
+struct WcdmaSignalStrength {
+ @1.0::WcdmaSignalStrength base;
+ /**
+ * CPICH RSCP as defined in TS 25.215 5.1.1
+ * Valid values are (0-96, 255) as defined in TS 27.007 8.69
+ */
+ uint32_t rscp;
+ /**
+ * Ec/No value as defined in TS 25.215 5.1.5
+ * Valid values are (0-49, 255) as defined in TS 27.007 8.69
+ */
+ uint32_t ecno;
+
+};
+
+struct TdscdmaSignalStrength {
+ /**
+ * UTRA carrier RSSI as defined in TS 25.225 5.1.4
+ * Valid values are (0-96, 99) as defined in TS 27.007 8.69
+ */
+ uint32_t signalStrength;
+ /**
+ * Transport Channel BER as defined in TS 25.225 5.2.5
+ * Valid values are (0-49, 99) as defined in TS 27.007 8.69
+ */
+ uint32_t bitErrorRate;
+ /**
+ * P-CCPCH RSCP as defined in TS 25.225 5.1.1
+ * Valid values are (0-96, 255) as defined in TS 27.007 8.69
+ */
+ uint32_t rscp;
+};
+
+struct SignalStrength {
+ GsmSignalStrength gsm;
+ CdmaSignalStrength cdma;
+ EvdoSignalStrength evdo;
+ LteSignalStrength lte;
+ TdScdmaSignalStrength tdScdma;
+ WcdmaSignalStrength wcdma;
+};
diff --git a/radio/1.2/vts/functional/radio_hidl_hal_api.cpp b/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
index 64a598a..06a7f77 100644
--- a/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
@@ -43,13 +43,9 @@
ALOGI("startNetworkScan, rspInfo.error = %s\n", toString(radioRsp_v1_2->rspInfo.error).c_str());
if (cardStatus.cardState == CardState::ABSENT) {
- ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
- {RadioError::SIM_ABSENT, RadioError::REQUEST_NOT_SUPPORTED,
- RadioError::OPERATION_NOT_ALLOWED}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::SIM_ABSENT}));
} else if (cardStatus.cardState == CardState::PRESENT) {
- ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
- {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED,
- RadioError::OPERATION_NOT_ALLOWED}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::NONE}));
}
}
@@ -73,12 +69,10 @@
toString(radioRsp_v1_2->rspInfo.error).c_str());
if (cardStatus.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
- {RadioError::SIM_ABSENT, RadioError::REQUEST_NOT_SUPPORTED,
- RadioError::INVALID_ARGUMENTS}));
+ {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.cardState == CardState::PRESENT) {
ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
- {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+ CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
}
@@ -110,15 +104,11 @@
ALOGI("startNetworkScan_InvalidInterval1, rspInfo.error = %s\n",
toString(radioRsp_v1_2->rspInfo.error).c_str());
if (cardStatus.cardState == CardState::ABSENT) {
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_v1_2->rspInfo.error,
- {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS,
- RadioError::REQUEST_NOT_SUPPORTED, RadioError::OPERATION_NOT_ALLOWED}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
+ {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.cardState == CardState::PRESENT) {
ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
- {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED,
- RadioError::OPERATION_NOT_ALLOWED}));
+ CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
}
@@ -150,15 +140,11 @@
ALOGI("startNetworkScan_InvalidInterval2, rspInfo.error = %s\n",
toString(radioRsp_v1_2->rspInfo.error).c_str());
if (cardStatus.cardState == CardState::ABSENT) {
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_v1_2->rspInfo.error,
- {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS,
- RadioError::REQUEST_NOT_SUPPORTED, RadioError::OPERATION_NOT_ALLOWED}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
+ {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.cardState == CardState::PRESENT) {
ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
- {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED,
- RadioError::OPERATION_NOT_ALLOWED}));
+ CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
}
@@ -190,15 +176,11 @@
ALOGI("startNetworkScan_InvalidMaxSearchTime1, rspInfo.error = %s\n",
toString(radioRsp_v1_2->rspInfo.error).c_str());
if (cardStatus.cardState == CardState::ABSENT) {
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_v1_2->rspInfo.error,
- {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS,
- RadioError::REQUEST_NOT_SUPPORTED, RadioError::OPERATION_NOT_ALLOWED}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
+ {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.cardState == CardState::PRESENT) {
ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
- {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED,
- RadioError::OPERATION_NOT_ALLOWED}));
+ CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
}
@@ -230,15 +212,11 @@
ALOGI("startNetworkScan_InvalidMaxSearchTime2, rspInfo.error = %s\n",
toString(radioRsp_v1_2->rspInfo.error).c_str());
if (cardStatus.cardState == CardState::ABSENT) {
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_v1_2->rspInfo.error,
- {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS,
- RadioError::REQUEST_NOT_SUPPORTED, RadioError::OPERATION_NOT_ALLOWED}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
+ {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.cardState == CardState::PRESENT) {
ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
- {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED,
- RadioError::OPERATION_NOT_ALLOWED}));
+ CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
}
@@ -270,15 +248,11 @@
ALOGI("startNetworkScan_InvalidPeriodicity1, rspInfo.error = %s\n",
toString(radioRsp_v1_2->rspInfo.error).c_str());
if (cardStatus.cardState == CardState::ABSENT) {
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_v1_2->rspInfo.error,
- {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS,
- RadioError::REQUEST_NOT_SUPPORTED, RadioError::OPERATION_NOT_ALLOWED}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
+ {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.cardState == CardState::PRESENT) {
ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
- {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED,
- RadioError::OPERATION_NOT_ALLOWED}));
+ CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
}
@@ -310,15 +284,11 @@
ALOGI("startNetworkScan_InvalidPeriodicity2, rspInfo.error = %s\n",
toString(radioRsp_v1_2->rspInfo.error).c_str());
if (cardStatus.cardState == CardState::ABSENT) {
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_v1_2->rspInfo.error,
- {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS,
- RadioError::REQUEST_NOT_SUPPORTED, RadioError::OPERATION_NOT_ALLOWED}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
+ {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.cardState == CardState::PRESENT) {
ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
- {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED,
- RadioError::OPERATION_NOT_ALLOWED}));
+ CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
}
@@ -350,14 +320,10 @@
ALOGI("startNetworkScan_InvalidArgument, rspInfo.error = %s\n",
toString(radioRsp_v1_2->rspInfo.error).c_str());
if (cardStatus.cardState == CardState::ABSENT) {
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_v1_2->rspInfo.error,
- {RadioError::NONE, RadioError::SIM_ABSENT, RadioError::REQUEST_NOT_SUPPORTED,
- RadioError::OPERATION_NOT_ALLOWED}));
- } else if (cardStatus.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
- {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED,
- RadioError::OPERATION_NOT_ALLOWED}));
+ {RadioError::NONE, RadioError::SIM_ABSENT}));
+ } else if (cardStatus.cardState == CardState::PRESENT) {
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::NONE}));
}
}
@@ -390,13 +356,9 @@
ALOGI("startNetworkScan_InvalidArgument, rspInfo.error = %s\n",
toString(radioRsp_v1_2->rspInfo.error).c_str());
if (cardStatus.cardState == CardState::ABSENT) {
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_v1_2->rspInfo.error,
- {RadioError::NONE, RadioError::SIM_ABSENT, RadioError::REQUEST_NOT_SUPPORTED,
- RadioError::OPERATION_NOT_ALLOWED}));
- } else if (cardStatus.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
- {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED,
- RadioError::OPERATION_NOT_ALLOWED}));
+ {RadioError::NONE, RadioError::SIM_ABSENT}));
+ } else if (cardStatus.cardState == CardState::PRESENT) {
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::NONE}));
}
}
diff --git a/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
index 97956c5..59ac13e 100644
--- a/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
+++ b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
@@ -30,6 +30,7 @@
#include <android/hardware/soundtrigger/2.0/types.h>
#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
#define SHORT_TIMEOUT_PERIOD (1)
@@ -85,12 +86,27 @@
int mCount;
};
+// Test environment for SoundTrigger HIDL HAL.
+class SoundTriggerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static SoundTriggerHidlEnvironment* Instance() {
+ static SoundTriggerHidlEnvironment* instance = new SoundTriggerHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<ISoundTriggerHw>(); }
+
+ private:
+ SoundTriggerHidlEnvironment() {}
+};
+
// The main test class for Sound Trigger HIDL HAL.
class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
virtual void SetUp() override {
- mSoundTriggerHal =
- ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>();
+ mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>(
+ SoundTriggerHidlEnvironment::Instance()->getServiceName<ISoundTriggerHw>());
ASSERT_NE(nullptr, mSoundTriggerHal.get());
mCallback = new SoundTriggerHwCallback(*this);
ASSERT_NE(nullptr, mCallback.get());
@@ -142,15 +158,6 @@
sp<SoundTriggerHwCallback> mCallback;
};
-// A class for test environment setup (kept since this file is a template).
-class SoundTriggerHidlEnvironment : public ::testing::Environment {
- public:
- virtual void SetUp() {}
- virtual void TearDown() {}
-
- private:
-};
-
/**
* Test ISoundTriggerHw::getProperties() method
*
@@ -318,11 +325,11 @@
EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS);
}
-
int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(new SoundTriggerHidlEnvironment);
- ::testing::InitGoogleTest(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
+ ::testing::AddGlobalTestEnvironment(SoundTriggerHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ SoundTriggerHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
}
diff --git a/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp b/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
index fdd5f0d..0a2eeac 100644
--- a/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
+++ b/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
@@ -33,6 +33,7 @@
#include <hidlmemory/mapping.h>
#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
#define SHORT_TIMEOUT_PERIOD (1)
@@ -93,11 +94,27 @@
int mCount;
};
+// Test environment for SoundTrigger HIDL HAL.
+class SoundTriggerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static SoundTriggerHidlEnvironment* Instance() {
+ static SoundTriggerHidlEnvironment* instance = new SoundTriggerHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<ISoundTriggerHw>(); }
+
+ private:
+ SoundTriggerHidlEnvironment() {}
+};
+
// The main test class for Sound Trigger HIDL HAL.
class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
virtual void SetUp() override {
- mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>();
+ mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>(
+ SoundTriggerHidlEnvironment::Instance()->getServiceName<ISoundTriggerHw>());
ASSERT_NE(nullptr, mSoundTriggerHal.get());
mCallback = new SoundTriggerHwCallback(*this);
ASSERT_NE(nullptr, mCallback.get());
@@ -480,3 +497,12 @@
EXPECT_TRUE(hidlReturn.isOk());
EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS);
}
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(SoundTriggerHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ SoundTriggerHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp b/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp
index dfa11a1..6f059ef 100644
--- a/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp
+++ b/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp
@@ -21,10 +21,11 @@
#define LOG_TAG "thermal_hidl_hal_test"
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android/hardware/thermal/1.0/IThermal.h>
#include <android/hardware/thermal/1.0/types.h>
-#include <VtsHalHidlTargetTestBase.h>
#include <unistd.h>
using ::android::hardware::hidl_string;
@@ -45,11 +46,26 @@
#define MAX_DEVICE_TEMPERATURE 200
#define MAX_FAN_SPEED 20000
+// Test environment for Thermal HIDL HAL.
+class ThermalHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static ThermalHidlEnvironment* Instance() {
+ static ThermalHidlEnvironment* instance = new ThermalHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<IThermal>(); }
+ private:
+ ThermalHidlEnvironment() {}
+};
+
// The main test class for THERMAL HIDL HAL.
class ThermalHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
virtual void SetUp() override {
- thermal_ = ::testing::VtsHalHidlTargetTestBase::getService<IThermal>();
+ thermal_ = ::testing::VtsHalHidlTargetTestBase::getService<IThermal>(
+ ThermalHidlEnvironment::Instance()->getServiceName<IThermal>());
ASSERT_NE(thermal_, nullptr);
baseSize_ = 0;
names_.clear();
@@ -207,7 +223,9 @@
}
int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(ThermalHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
+ ThermalHidlEnvironment::Instance()->init(&argc, argv);
int status = RUN_ALL_TESTS();
LOG(INFO) << "Test result = " << status;
return status;
diff --git a/thermal/1.1/vts/functional/VtsHalThermalV1_1TargetTest.cpp b/thermal/1.1/vts/functional/VtsHalThermalV1_1TargetTest.cpp
index 6c1599b..91c8b6e 100644
--- a/thermal/1.1/vts/functional/VtsHalThermalV1_1TargetTest.cpp
+++ b/thermal/1.1/vts/functional/VtsHalThermalV1_1TargetTest.cpp
@@ -20,6 +20,7 @@
#include <VtsHalHidlTargetCallbackBase.h>
#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
using ::android::hardware::thermal::V1_0::Temperature;
using ::android::hardware::thermal::V1_0::TemperatureType;
@@ -62,11 +63,26 @@
}
};
+// Test environment for Thermal HIDL HAL.
+class ThermalHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static ThermalHidlEnvironment* Instance() {
+ static ThermalHidlEnvironment* instance = new ThermalHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<IThermal>(); }
+ private:
+ ThermalHidlEnvironment() {}
+};
+
// The main test class for THERMAL HIDL HAL 1.1.
class ThermalHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
virtual void SetUp() override {
- mThermal = ::testing::VtsHalHidlTargetTestBase::getService<IThermal>();
+ mThermal = ::testing::VtsHalHidlTargetTestBase::getService<IThermal>(
+ ThermalHidlEnvironment::Instance()->getServiceName<IThermal>());
ASSERT_NE(mThermal, nullptr);
mThermalCallback = new(std::nothrow) ThermalCallback();
ASSERT_NE(mThermalCallback, nullptr);
@@ -99,7 +115,9 @@
}
int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(ThermalHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
+ ThermalHidlEnvironment::Instance()->init(&argc, argv);
int status = RUN_ALL_TESTS();
cout << "Test result = " << status << std::endl;
return status;
diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp
index ea27f02..b2f76a3 100644
--- a/wifi/1.0/vts/functional/Android.bp
+++ b/wifi/1.0/vts/functional/Android.bp
@@ -20,7 +20,8 @@
srcs: [
"wifi_hidl_call_util_selftest.cpp",
"wifi_hidl_test.cpp",
- "wifi_hidl_test_utils.cpp"],
+ "wifi_hidl_test_utils.cpp",
+ ],
export_include_dirs: [
"."
],
diff --git a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
index beac039..e7b8593 100644
--- a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
+++ b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
@@ -16,16 +16,31 @@
#include <android-base/logging.h>
-#include <VtsHalHidlTargetTestBase.h>
-
#include "wifi_hidl_test_utils.h"
-WifiHidlEnvironment* gEnv;
+class WifiVtsHidlEnvironment_1_0 : public WifiHidlEnvironment {
+ public:
+ // get the test environment singleton
+ static WifiVtsHidlEnvironment_1_0* Instance() {
+ static WifiVtsHidlEnvironment_1_0* instance =
+ new WifiVtsHidlEnvironment_1_0;
+ return instance;
+ }
+
+ virtual void registerTestServices() override {
+ registerTestService<android::hardware::wifi::V1_0::IWifi>();
+ }
+
+ private:
+ WifiVtsHidlEnvironment_1_0() {}
+};
+
+WifiHidlEnvironment* gEnv = WifiVtsHidlEnvironment_1_0::Instance();
int main(int argc, char** argv) {
- gEnv = new WifiHidlEnvironment();
::testing::AddGlobalTestEnvironment(gEnv);
::testing::InitGoogleTest(&argc, argv);
+ gEnv->init(&argc, argv);
int status = gEnv->initFromOptions(argc, argv);
if (status == 0) {
status = RUN_ALL_TESTS();
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
index 313bdd8..97a371b 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
@@ -35,6 +35,8 @@
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
+extern WifiHidlEnvironment* gEnv;
+
namespace {
constexpr uint32_t kHalStartRetryMaxCount = 5;
constexpr uint32_t kHalStartRetryIntervalInMs = 2;
@@ -86,7 +88,8 @@
} // namespace
sp<IWifi> getWifi() {
- sp<IWifi> wifi = ::testing::VtsHalHidlTargetTestBase::getService<IWifi>();
+ sp<IWifi> wifi = ::testing::VtsHalHidlTargetTestBase::getService<IWifi>(
+ gEnv->getServiceName<IWifi>());
return wifi;
}
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
index c4a19dd..2b1c8ec 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
@@ -26,6 +26,7 @@
#include <getopt.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
// Helper functions to obtain references to the various HIDL interface objects.
// Note: We only have a single instance of each of these objects currently.
// These helper functions should be modified to return vectors if we support
@@ -47,9 +48,9 @@
// Used to trigger IWifi.stop() at the end of every test.
void stopWifi();
-class WifiHidlEnvironment : public ::testing::Environment {
+class WifiHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
protected:
- virtual void SetUp() override {
+ virtual void HidlSetUp() override {
stopWifi();
sleep(5);
}
diff --git a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
index 9b92b57..a0f97f8 100644
--- a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
+++ b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
@@ -15,17 +15,32 @@
*/
#include <android-base/logging.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/wifi/1.1/IWifi.h>
#include "wifi_hidl_test_utils.h"
-WifiHidlEnvironment* gEnv;
+class WifiHidlEnvironment_1_1 : public WifiHidlEnvironment {
+ public:
+ // get the test environment singleton
+ static WifiHidlEnvironment_1_1* Instance() {
+ static WifiHidlEnvironment_1_1* instance = new WifiHidlEnvironment_1_1;
+ return instance;
+ }
+
+ virtual void registerTestServices() override {
+ registerTestService<android::hardware::wifi::V1_1::IWifi>();
+ }
+
+ private:
+ WifiHidlEnvironment_1_1() {}
+};
+
+WifiHidlEnvironment* gEnv = WifiHidlEnvironment_1_1::Instance();
int main(int argc, char** argv) {
- gEnv = new WifiHidlEnvironment();
::testing::AddGlobalTestEnvironment(gEnv);
::testing::InitGoogleTest(&argc, argv);
+ gEnv->init(&argc, argv);
int status = gEnv->initFromOptions(argc, argv);
if (status == 0) {
int status = RUN_ALL_TESTS();
diff --git a/wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp b/wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp
index 64e6fbe..0303b20 100644
--- a/wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp
+++ b/wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp
@@ -15,20 +15,34 @@
*/
#include <android-base/logging.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
#include "hostapd_hidl_test_utils.h"
-class HostapdHidlEnvironment : public ::testing::Environment {
+class WifiHostapdHidlEnvironment_1_0 : public WifiHostapdHidlEnvironment {
public:
- virtual void SetUp() override { stopHostapd(); }
- virtual void TearDown() override { startHostapdAndWaitForHidlService(); }
+ // get the test environment singleton
+ static WifiHostapdHidlEnvironment_1_0* Instance() {
+ static WifiHostapdHidlEnvironment_1_0* instance =
+ new WifiHostapdHidlEnvironment_1_0;
+ return instance;
+ }
+
+ virtual void registerTestServices() override {
+ registerTestService<::android::hardware::wifi::V1_0::IWifi>();
+ registerTestService<android::hardware::wifi::hostapd::V1_0::IHostapd>();
+ }
+
+ private:
+ WifiHostapdHidlEnvironment_1_0() {}
};
+WifiHostapdHidlEnvironment* gEnv = WifiHostapdHidlEnvironment_1_0::Instance();
+
int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(new HostapdHidlEnvironment);
+ ::testing::AddGlobalTestEnvironment(gEnv);
::testing::InitGoogleTest(&argc, argv);
+ gEnv->init(&argc, argv);
int status = RUN_ALL_TESTS();
LOG(INFO) << "Test result = " << status;
return status;
diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
index 0915150..e5ba8ef 100644
--- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
+++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
@@ -42,9 +42,9 @@
using ::android::hidl::manager::V1_0::IServiceNotification;
using ::android::wifi_system::HostapdManager;
-namespace {
-const char kHostapdServiceName[] = "default";
+extern WifiHostapdHidlEnvironment* gEnv;
+namespace {
// Helper function to initialize the driver and firmware to AP mode
// using the vendor HAL HIDL interface.
void initilializeDriverAndFirmware() {
@@ -120,16 +120,17 @@
android::sp<ServiceNotificationListener> notification_listener =
new ServiceNotificationListener();
+ string service_name = gEnv->getServiceName<IHostapd>();
ASSERT_TRUE(notification_listener->registerForHidlServiceNotifications(
- kHostapdServiceName));
+ service_name));
HostapdManager hostapd_manager;
ASSERT_TRUE(hostapd_manager.StartHostapd());
- ASSERT_TRUE(
- notification_listener->waitForHidlService(200, kHostapdServiceName));
+ ASSERT_TRUE(notification_listener->waitForHidlService(200, service_name));
}
sp<IHostapd> getHostapd() {
- return ::testing::VtsHalHidlTargetTestBase::getService<IHostapd>();
+ return ::testing::VtsHalHidlTargetTestBase::getService<IHostapd>(
+ gEnv->getServiceName<IHostapd>());
}
diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h
index 74ed284..1b92477 100644
--- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h
+++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h
@@ -19,6 +19,8 @@
#include <android/hardware/wifi/hostapd/1.0/IHostapd.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+
// Used to stop the android wifi framework before every test.
void stopWifiFramework();
void startWifiFramework();
@@ -33,4 +35,13 @@
// multiple instances.
android::sp<android::hardware::wifi::hostapd::V1_0::IHostapd> getHostapd();
+class WifiHostapdHidlEnvironment
+ : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ virtual void HidlSetUp() override { stopHostapd(); }
+ virtual void HidlTearDown() override {
+ startHostapdAndWaitForHidlService();
+ }
+};
+
#endif /* HOSTAPD_HIDL_TEST_UTILS_H */
diff --git a/wifi/offload/1.0/vts/functional/VtsHalWifiOffloadV1_0TargetTest.cpp b/wifi/offload/1.0/vts/functional/VtsHalWifiOffloadV1_0TargetTest.cpp
index 90c36dd..dbe4e74 100644
--- a/wifi/offload/1.0/vts/functional/VtsHalWifiOffloadV1_0TargetTest.cpp
+++ b/wifi/offload/1.0/vts/functional/VtsHalWifiOffloadV1_0TargetTest.cpp
@@ -23,6 +23,7 @@
#include <VtsHalHidlTargetCallbackBase.h>
#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
#include <vector>
@@ -68,12 +69,33 @@
OffloadStatus error_code_;
};
+// Test environment for Weaver HIDL HAL.
+class WifiOffloadHidlEnvironment
+ : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static WifiOffloadHidlEnvironment* Instance() {
+ static WifiOffloadHidlEnvironment* instance =
+ new WifiOffloadHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override {
+ registerTestService<IOffload>();
+ }
+
+ private:
+ WifiOffloadHidlEnvironment() {}
+};
+
// The main test class for WifiOffload HIDL HAL.
class WifiOffloadHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
virtual void SetUp() override {
wifi_offload_ =
- ::testing::VtsHalHidlTargetTestBase::getService<IOffload>();
+ ::testing::VtsHalHidlTargetTestBase::getService<IOffload>(
+ WifiOffloadHidlEnvironment::Instance()
+ ->getServiceName<IOffload>());
ASSERT_NE(wifi_offload_, nullptr);
wifi_offload_cb_ = new OffloadCallback();
@@ -209,17 +231,10 @@
ASSERT_EQ(true, res.no_timeout);
}
-// A class for test environment setup
-class WifiOffloadHalHidlEnvironment : public ::testing::Environment {
- public:
- virtual void SetUp() {}
- virtual void TearDown() {}
-};
-
int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(new WifiOffloadHalHidlEnvironment);
+ ::testing::AddGlobalTestEnvironment(WifiOffloadHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
-
+ WifiOffloadHidlEnvironment::Instance()->init(&argc, argv);
int status = RUN_ALL_TESTS();
LOG(INFO) << "Test result = " << status;
diff --git a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp
index 7fa20c9..adf2a85 100644
--- a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp
+++ b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp
@@ -16,21 +16,34 @@
#include <android-base/logging.h>
-#include <VtsHalHidlTargetTestBase.h>
-
#include "supplicant_hidl_test_utils.h"
+#include "wifi_hidl_test_utils.h"
-class SupplicantHidlEnvironment : public ::testing::Environment {
+class WifiSupplicantHidlEnvironment_1_0 : public WifiSupplicantHidlEnvironment {
public:
- virtual void SetUp() override {
- stopSupplicant();
+ // get the test environment singleton
+ static WifiSupplicantHidlEnvironment_1_0* Instance() {
+ static WifiSupplicantHidlEnvironment_1_0* instance =
+ new WifiSupplicantHidlEnvironment_1_0;
+ return instance;
}
- virtual void TearDown() override { startSupplicantAndWaitForHidlService(); }
+ virtual void registerTestServices() override {
+ registerTestService<::android::hardware::wifi::V1_0::IWifi>();
+ registerTestService<
+ ::android::hardware::wifi::supplicant::V1_0::ISupplicant>();
+ }
+
+ private:
+ WifiSupplicantHidlEnvironment_1_0() {}
};
+WifiSupplicantHidlEnvironment* gEnv =
+ WifiSupplicantHidlEnvironment_1_0::Instance();
+
int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(new SupplicantHidlEnvironment);
+ ::testing::AddGlobalTestEnvironment(gEnv);
::testing::InitGoogleTest(&argc, argv);
+ gEnv->init(&argc, argv);
int status = RUN_ALL_TESTS();
LOG(INFO) << "Test result = " << status;
return status;
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
index 3b75508..6dd64ec 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include <android-base/logging.h>
#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <android/hidl/manager/1.0/IServiceNotification.h>
@@ -49,8 +49,9 @@
using ::android::wifi_system::InterfaceTool;
using ::android::wifi_system::SupplicantManager;
+extern WifiSupplicantHidlEnvironment* gEnv;
+
namespace {
-const char kSupplicantServiceName[] = "default";
// Helper function to initialize the driver and firmware to STA mode
// using the vendor HAL HIDL interface.
@@ -153,19 +154,20 @@
android::sp<ServiceNotificationListener> notification_listener =
new ServiceNotificationListener();
+ string service_name = gEnv->getServiceName<ISupplicant>();
ASSERT_TRUE(notification_listener->registerForHidlServiceNotifications(
- kSupplicantServiceName));
+ service_name));
SupplicantManager supplicant_manager;
ASSERT_TRUE(supplicant_manager.StartSupplicant());
ASSERT_TRUE(supplicant_manager.IsSupplicantRunning());
- ASSERT_TRUE(
- notification_listener->waitForHidlService(200, kSupplicantServiceName));
+ ASSERT_TRUE(notification_listener->waitForHidlService(200, service_name));
}
sp<ISupplicant> getSupplicant() {
- return ::testing::VtsHalHidlTargetTestBase::getService<ISupplicant>();
+ return ::testing::VtsHalHidlTargetTestBase::getService<ISupplicant>(
+ gEnv->getServiceName<ISupplicant>());
}
sp<ISupplicantStaIface> getSupplicantStaIface() {
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
index 38143e4..4426ab6 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
@@ -22,6 +22,8 @@
#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIface.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+
// Used to stop the android wifi framework before every test.
void stopWifiFramework();
void startWifiFramework();
@@ -45,4 +47,13 @@
bool turnOnExcessiveLogging();
+class WifiSupplicantHidlEnvironment
+ : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ virtual void HidlSetUp() override { stopSupplicant(); }
+ virtual void HidlTearDown() override {
+ startSupplicantAndWaitForHidlService();
+ }
+};
+
#endif /* SUPPLICANT_HIDL_TEST_UTILS_H */
diff --git a/wifi/supplicant/1.1/vts/functional/Android.bp b/wifi/supplicant/1.1/vts/functional/Android.bp
index 9375cf5..188dba3 100644
--- a/wifi/supplicant/1.1/vts/functional/Android.bp
+++ b/wifi/supplicant/1.1/vts/functional/Android.bp
@@ -48,6 +48,7 @@
"android.hardware.wifi.supplicant@1.0",
"android.hardware.wifi.supplicant@1.1",
"android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
"libcrypto",
"libgmock",
"libwifi-system",
diff --git a/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp b/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp
index b5e369a..3d24fc3 100644
--- a/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp
+++ b/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp
@@ -15,20 +15,37 @@
*/
#include <android-base/logging.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/wifi/1.1/IWifi.h>
+#include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
#include "supplicant_hidl_test_utils.h"
+#include "wifi_hidl_test_utils.h"
-class SupplicantHidlEnvironment : public ::testing::Environment {
+class WifiSupplicantHidlEnvironment_1_1 : public WifiSupplicantHidlEnvironment {
public:
- virtual void SetUp() override { stopSupplicant(); }
- virtual void TearDown() override { startSupplicantAndWaitForHidlService(); }
+ // get the test environment singleton
+ static WifiSupplicantHidlEnvironment_1_1* Instance() {
+ static WifiSupplicantHidlEnvironment_1_1* instance =
+ new WifiSupplicantHidlEnvironment_1_1;
+ return instance;
+ }
+ virtual void registerTestServices() override {
+ registerTestService<::android::hardware::wifi::V1_1::IWifi>();
+ registerTestService<
+ ::android::hardware::wifi::supplicant::V1_1::ISupplicant>();
+ }
+
+ private:
+ WifiSupplicantHidlEnvironment_1_1() {}
};
+WifiSupplicantHidlEnvironment* gEnv =
+ WifiSupplicantHidlEnvironment_1_1::Instance();
+
int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(new SupplicantHidlEnvironment);
+ ::testing::AddGlobalTestEnvironment(gEnv);
::testing::InitGoogleTest(&argc, argv);
+ gEnv->init(&argc, argv);
int status = RUN_ALL_TESTS();
LOG(INFO) << "Test result = " << status;
return status;