[automerger skipped] DO NOT MERGE: audio: Skip tests if audio HAL service lacks "primary" device
am: 1ed70316c5 -s ours
am skip reason: subject contains skip directive

Change-Id: Idb5bb585dc22bd6027f1177bbb90392aad464d4b
diff --git a/audio/4.0/config/audio_policy_configuration.xsd b/audio/4.0/config/audio_policy_configuration.xsd
index f26e41b..58bab22 100644
--- a/audio/4.0/config/audio_policy_configuration.xsd
+++ b/audio/4.0/config/audio_policy_configuration.xsd
@@ -357,10 +357,6 @@
             <xs:enumeration value="AUDIO_FORMAT_APTX_HD"/>
             <xs:enumeration value="AUDIO_FORMAT_AC4"/>
             <xs:enumeration value="AUDIO_FORMAT_LDAC"/>
-            <xs:enumeration value="AUDIO_FORMAT_E_AC3_JOC"/>
-            <xs:enumeration value="AUDIO_FORMAT_MAT_1_0"/>
-            <xs:enumeration value="AUDIO_FORMAT_MAT_2_0"/>
-            <xs:enumeration value="AUDIO_FORMAT_MAT_2_1"/>
         </xs:restriction>
     </xs:simpleType>
     <xs:simpleType name="extendableAudioFormat">
diff --git a/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc b/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc
index 8217b94..6e91bcc 100644
--- a/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc
+++ b/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc
@@ -2,7 +2,8 @@
     class hal
     user audioserver
     # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
-    group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
+    group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock
+    capabilities BLOCK_SUSPEND
     ioprio rt 4
     writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
     # audioflinger restarts itself when it loses connection with the hal
diff --git a/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp
index 545d6c0..46c228a 100644
--- a/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp
@@ -155,11 +155,6 @@
    protected:
     // Cache the devicesFactory retrieval to speed up each test by ~0.5s
     static sp<IDevicesFactory> devicesFactory;
-
-    static bool isPrimaryDeviceOptional() {
-        // It's OK not to have "primary" device on non-default audio HAL service.
-        return environment->getServiceName<IDevicesFactory>() != kDefaultServiceName;
-    }
 };
 sp<IDevicesFactory> AudioHidlTest::devicesFactory;
 
@@ -176,7 +171,19 @@
     ASSERT_TRUE(device == nullptr);
 }
 
-static void waitForDeviceDestruction() {
+TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
+    doc::test("Calling openDevice(\"primary\") should return the primary device.");
+    {
+        Result result;
+        sp<IDevice> baseDevice;
+        ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice)));
+        ASSERT_OK(result);
+        ASSERT_TRUE(baseDevice != nullptr);
+
+        Return<sp<IPrimaryDevice>> primaryDevice = IPrimaryDevice::castFrom(baseDevice);
+        ASSERT_TRUE(primaryDevice.isOk());
+        ASSERT_TRUE(sp<IPrimaryDevice>(primaryDevice) != nullptr);
+    }  // Destroy local IDevice proxy
     // FIXME: there is no way to know when the remote IDevice is being destroyed
     //        Binder does not support testing if an object is alive, thus
     //        wait for 100ms to let the binder destruction propagates and
@@ -184,26 +191,7 @@
     //        flushCommand makes sure all local command are sent, thus should reduce
     //        the latency between local and remote destruction.
     IPCThreadState::self()->flushCommands();
-    usleep(100*1000);
-}
-
-TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
-    doc::test("Calling openDevice(\"primary\") should return the primary device.");
-    struct WaitExecutor {
-        ~WaitExecutor() { waitForDeviceDestruction(); }
-    } waitExecutor;  // Make sure we wait for the device destruction on exiting from the test.
-    Result result;
-    sp<IDevice> baseDevice;
-    ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice)));
-    if (result != Result::OK && isPrimaryDeviceOptional()) {
-        return SUCCEED() << "No primary device on this factory";
-    }
-    ASSERT_OK(result);
-    ASSERT_TRUE(baseDevice != nullptr);
-
-    Return<sp<IPrimaryDevice>> primaryDevice = IPrimaryDevice::castFrom(baseDevice);
-    ASSERT_TRUE(primaryDevice.isOk());
-    ASSERT_TRUE(sp<IPrimaryDevice>(primaryDevice) != nullptr);
+    usleep(100);
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -216,44 +204,29 @@
     /** Primary HAL test are NOT thread safe. */
     void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp());  // setup base
+
         if (device == nullptr) {
-            initPrimaryDevice();
-            if (device == nullptr && isPrimaryDeviceOptional()) {
-                return SUCCEED() << "No primary device on this factory";
-            }
+            Result result;
+            ASSERT_OK(devicesFactory->openPrimaryDevice(returnIn(result, device)));
+            ASSERT_OK(result);
+            ASSERT_TRUE(device != nullptr);
+
+            environment->registerTearDown([] { device.clear(); });
         }
-        ASSERT_TRUE(device != nullptr);
     }
 
    protected:
     // Cache the device opening to speed up each test by ~0.5s
     static sp<IPrimaryDevice> device;
-
-    static void initPrimaryDevice() {
-        ASSERT_TRUE(devicesFactory != nullptr);
-        Result result;
-        ASSERT_OK(devicesFactory->openPrimaryDevice(returnIn(result, device)));
-        ASSERT_OK(result);
-        if (device != nullptr) {
-            environment->registerTearDown([] { device.clear(); });
-        }
-    }
 };
 sp<IPrimaryDevice> AudioPrimaryHidlTest::device;
 
-#define SKIP_IF_NO_DEVICE                                       \
-    if (!device) {                                              \
-        doc::partialTest("No primary device on this factory");  \
-        return;                                                 \
-    }                                                           \
-
 TEST_F(AudioPrimaryHidlTest, OpenPrimaryDevice) {
     doc::test("Test the openDevice (called in SetUp)");
 }
 
 TEST_F(AudioPrimaryHidlTest, Init) {
     doc::test("Test that the audio primary hal initialized correctly");
-    SKIP_IF_NO_DEVICE;
     ASSERT_OK(device->initCheck());
 }
 
@@ -277,7 +250,6 @@
     void testAccessors(const string& propertyName, const Initial expectedInitial,
                        list<Property> valuesToTest, Setter setter, Getter getter,
                        const vector<Property>& invalidValues = {}) {
-        SKIP_IF_NO_DEVICE;
         const auto expectedResults = {Result::OK,
                                       optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK};
 
@@ -360,7 +332,6 @@
 
 TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) {
     doc::test("Test if audio patches are supported");
-    SKIP_IF_NO_DEVICE;
     if (!areAudioPatchesSupported()) {
         doc::partialTest("Audio patches are not supported");
         return;
@@ -460,7 +431,6 @@
                                       public ::testing::WithParamInterface<AudioConfig> {
    protected:
     void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) {
-        SKIP_IF_NO_DEVICE;
         uint64_t bufferSize;
         ASSERT_OK(device->getInputBufferSize(audioConfig, returnIn(res, bufferSize)));
 
@@ -517,7 +487,6 @@
 
 TEST_F(AudioPrimaryHidlTest, setScreenState) {
     doc::test("Check that the hal can receive the screen state");
-    SKIP_IF_NO_DEVICE;
     for (bool turnedOn : {false, true, true, false, false}) {
         ASSERT_RESULT(okOrNotSupported, device->setScreenState(turnedOn));
     }
@@ -529,7 +498,6 @@
 
 TEST_F(AudioPrimaryHidlTest, getParameters) {
     doc::test("Check that the hal can set and get parameters");
-    SKIP_IF_NO_DEVICE;
     hidl_vec<ParameterValue> context;
     hidl_vec<hidl_string> keys;
     hidl_vec<ParameterValue> values;
@@ -545,7 +513,6 @@
 
 TEST_F(AudioPrimaryHidlTest, GetMicrophonesTest) {
     doc::test("Make sure getMicrophones always succeeds");
-    SKIP_IF_NO_DEVICE;
     hidl_vec<MicrophoneInfo> microphones;
     ASSERT_OK(device->getMicrophones(returnIn(res, microphones)));
     ASSERT_OK(res);
@@ -661,19 +628,16 @@
 
 TEST_F(AudioPrimaryHidlTest, DebugDump) {
     doc::test("Check that the hal can dump its state without error");
-    SKIP_IF_NO_DEVICE;
     testDebugDump([](const auto& handle) { return device->debug(handle, {/* options */}); });
 }
 
 TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) {
     doc::test("Check that the hal dump doesn't crash on invalid arguments");
-    SKIP_IF_NO_DEVICE;
     ASSERT_OK(device->debug(hidl_handle(), {/* options */}));
 }
 
 TEST_F(AudioPrimaryHidlTest, SetConnectedState) {
     doc::test("Check that the HAL can be notified of device connection and deconnection");
-    SKIP_IF_NO_DEVICE;
     using AD = AudioDevice;
     for (auto deviceType : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) {
         SCOPED_TRACE("device=" + ::testing::PrintToString(deviceType));
@@ -690,13 +654,6 @@
             ASSERT_OK(ret);
         }
     }
-
-    // Because there is no way of knowing if the devices were connected before
-    // calling setConnectedState, there is no way to restore the HAL to its
-    // initial state. To workaround this, destroy the HAL at the end of this test.
-    device.clear();
-    waitForDeviceDestruction();
-    ASSERT_NO_FATAL_FAILURE(initPrimaryDevice());
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -709,7 +666,6 @@
    protected:
     template <class Open>
     void testOpen(Open openStream, const AudioConfig& config) {
-        SKIP_IF_NO_DEVICE;
         // FIXME: Open a stream without an IOHandle
         //        This is not required to be accepted by hal implementations
         AudioIoHandle ioHandle = (AudioIoHandle)AudioHandleConsts::AUDIO_IO_HANDLE_NONE;
@@ -742,29 +698,14 @@
 
     Return<Result> closeStream() {
         open = false;
-        auto res = stream->close();
-        stream.clear();
-        waitForStreamDestruction();
-        return res;
-    }
-
-    void waitForStreamDestruction() {
-        // FIXME: there is no way to know when the remote IStream is being destroyed
-        //        Binder does not support testing if an object is alive, thus
-        //        wait for 100ms to let the binder destruction propagates and
-        //        the remote device has the time to be destroyed.
-        //        flushCommand makes sure all local command are sent, thus should reduce
-        //        the latency between local and remote destruction.
-        IPCThreadState::self()->flushCommands();
-        usleep(100*1000);
+        return stream->close();
     }
 
    private:
     void TearDown() override {
         if (open) {
-            ASSERT_OK(closeStream());
+            ASSERT_OK(stream->close());
         }
-        AudioConfigPrimaryTest::TearDown();
     }
 
    protected:
@@ -777,9 +718,8 @@
 ////////////////////////////// openOutputStream //////////////////////////////
 
 class OutputStreamTest : public OpenStreamTest<IStreamOut> {
-    void SetUp() override {
+    virtual void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp());  // setup base
-        if (!device && !HasFailure()) return;  // do not attempt to use 'device'
         address.device = AudioDevice::OUT_DEFAULT;
         const AudioConfig& config = GetParam();
         // TODO: test all flag combination
@@ -819,9 +759,8 @@
 ////////////////////////////// openInputStream //////////////////////////////
 
 class InputStreamTest : public OpenStreamTest<IStreamIn> {
-    void SetUp() override {
+    virtual void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp());  // setup base
-        if (!device && !HasFailure()) return;  // do not attempt to use 'device'
         address.device = AudioDevice::IN_DEFAULT;
         const AudioConfig& config = GetParam();
         // TODO: test all supported flags and source
@@ -872,23 +811,15 @@
     return ret;
 }
 
-#define SKIP_IF_NO_STREAM                                       \
-    if (!stream) {                                              \
-        doc::partialTest("No primary device on this factory");  \
-        return;                                                 \
-    }
-
 /* Could not find a way to write a test for two parametrized class fixure
  * thus use this macro do duplicate tests for Input and Output stream */
 #define TEST_IO_STREAM(test_name, documentation, code) \
     TEST_P(InputStreamTest, test_name) {               \
         doc::test(documentation);                      \
-        SKIP_IF_NO_STREAM;                             \
         code;                                          \
     }                                                  \
     TEST_P(OutputStreamTest, test_name) {              \
         doc::test(documentation);                      \
-        SKIP_IF_NO_STREAM;                             \
         code;                                          \
     }
 
@@ -917,7 +848,6 @@
                                  Return<Property> (IStream::*getter)(),
                                  Return<Result> (IStream::*setter)(Property),
                                  bool currentMustBeSupported = true) {
-    SKIP_IF_NO_STREAM;
     hidl_vec<Property> capabilities;
     auto ret = capablityGetter(stream, capabilities);
     if (ret == Result::NOT_SUPPORTED) {
@@ -987,7 +917,6 @@
                                     &IStream::getFormat, &IStream::setFormat))
 
 static void testGetDevices(IStream* stream, AudioDevice expectedDevice) {
-    SKIP_IF_NO_STREAM;
     hidl_vec<DeviceAddress> devices;
     Result res;
     ASSERT_OK(stream->getDevices(returnIn(res, devices)));
@@ -1007,7 +936,6 @@
                                           : testGetDevices(stream.get(), address.device))
 
 static void testSetDevices(IStream* stream, const DeviceAddress& address) {
-    SKIP_IF_NO_STREAM;
     DeviceAddress otherAddress = address;
     otherAddress.device = (address.device & AudioDevice::BIT_IN) == 0 ? AudioDevice::OUT_SPEAKER
                                                                       : AudioDevice::IN_BUILTIN_MIC;
@@ -1021,7 +949,6 @@
                                           : testSetDevices(stream.get(), address))
 
 static void testGetAudioProperties(IStream* stream, AudioConfig expectedConfig) {
-    SKIP_IF_NO_STREAM;
     uint32_t sampleRateHz;
     hidl_bitfield<AudioChannelMask> mask;
     AudioFormat format;
@@ -1043,7 +970,6 @@
                ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, stream->setHwAvSync(666)))
 
 static void checkGetHwAVSync(IDevice* device) {
-    SKIP_IF_NO_DEVICE;
     Result res;
     AudioHwSync sync;
     ASSERT_OK(device->getHwAvSync(returnIn(res, sync)));
@@ -1056,7 +982,6 @@
 
 static void checkGetNoParameter(IStream* stream, hidl_vec<hidl_string> keys,
                                 initializer_list<Result> expectedResults) {
-    SKIP_IF_NO_STREAM;
     hidl_vec<ParameterValue> context;
     hidl_vec<ParameterValue> parameters;
     Result res;
@@ -1126,15 +1051,10 @@
                ASSERT_RESULT(invalidStateOrNotSupported, stream->stop()))
 
 TEST_IO_STREAM(close, "Make sure a stream can be closed", ASSERT_OK(closeStream()))
-TEST_IO_STREAM(closeTwice, "Make sure a stream can not be closed twice",
-        auto streamCopy = stream;
-        ASSERT_OK(closeStream());
-        ASSERT_RESULT(Result::INVALID_STATE, streamCopy->close());
-        streamCopy.clear();
-        waitForStreamDestruction())
+TEST_IO_STREAM(closeTwice, "Make sure a stream can not be closed twice", ASSERT_OK(closeStream());
+               ASSERT_RESULT(Result::INVALID_STATE, closeStream()))
 
 static void testCreateTooBigMmapBuffer(IStream* stream) {
-    SKIP_IF_NO_STREAM;
     MmapBufferInfo info;
     Result res;
     // Assume that int max is a value too big to be allocated
@@ -1149,7 +1069,6 @@
                testCreateTooBigMmapBuffer(stream.get()))
 
 static void testGetMmapPositionOfNonMmapedStream(IStream* stream) {
-    SKIP_IF_NO_STREAM;
     Result res;
     MmapPosition position;
     ASSERT_OK(stream->getMmapPosition(returnIn(res, position)));
@@ -1166,7 +1085,6 @@
 
 TEST_P(InputStreamTest, GetAudioSource) {
     doc::test("Retrieving the audio source of an input stream should always succeed");
-    SKIP_IF_NO_STREAM;
     AudioSource source;
     ASSERT_OK(stream->getAudioSource(returnIn(res, source)));
     if (res == Result::NOT_SUPPORTED) {
@@ -1201,14 +1119,12 @@
 
 TEST_P(InputStreamTest, SetGain) {
     doc::test("The gain of an input stream should only be set between [0,1]");
-    SKIP_IF_NO_STREAM;
     testOptionalUnitaryGain([this](float volume) { return stream->setGain(volume); },
                             "InputStream::setGain");
 }
 
 static void testPrepareForReading(IStreamIn* stream, uint32_t frameSize, uint32_t framesCount) {
     Result res;
-    SKIP_IF_NO_STREAM;
     // Ignore output parameters as the call should fail
     ASSERT_OK(stream->prepareForReading(frameSize, framesCount,
                                         [&res](auto r, auto&, auto&, auto&, auto&) { res = r; }));
@@ -1217,13 +1133,11 @@
 
 TEST_P(InputStreamTest, PrepareForReadingWithZeroBuffer) {
     doc::test("Preparing a stream for reading with a 0 sized buffer should fail");
-    SKIP_IF_NO_STREAM;
     testPrepareForReading(stream.get(), 0, 0);
 }
 
 TEST_P(InputStreamTest, PrepareForReadingWithHugeBuffer) {
     doc::test("Preparing a stream for reading with a 2^32 sized buffer should fail");
-    SKIP_IF_NO_STREAM;
     testPrepareForReading(stream.get(), 1, std::numeric_limits<uint32_t>::max());
 }
 
@@ -1231,14 +1145,12 @@
     doc::test(
         "Preparing a stream for reading with a overflowing sized buffer should "
         "fail");
-    SKIP_IF_NO_STREAM;
     auto uintMax = std::numeric_limits<uint32_t>::max();
     testPrepareForReading(stream.get(), uintMax, uintMax);
 }
 
 TEST_P(InputStreamTest, GetInputFramesLost) {
     doc::test("The number of frames lost on a never started stream should be 0");
-    SKIP_IF_NO_STREAM;
     auto ret = stream->getInputFramesLost();
     ASSERT_IS_OK(ret);
     uint32_t framesLost{ret};
@@ -1249,7 +1161,6 @@
     doc::test(
         "The capture position of a non prepared stream should not be "
         "retrievable or 0");
-    SKIP_IF_NO_STREAM;
     uint64_t frames;
     uint64_t time;
     ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, time)));
@@ -1262,7 +1173,6 @@
 
 TEST_P(InputStreamTest, updateSinkMetadata) {
     doc::test("The HAL should not crash on metadata change");
-    SKIP_IF_NO_STREAM;
 
     hidl_enum_iterator<AudioSource> range;
     // Test all possible track configuration
@@ -1289,7 +1199,6 @@
 
 TEST_P(OutputStreamTest, getLatency) {
     doc::test("Make sure latency is over 0");
-    SKIP_IF_NO_STREAM;
     auto result = stream->getLatency();
     ASSERT_IS_OK(result);
     ASSERT_GT(result, 0U);
@@ -1297,14 +1206,12 @@
 
 TEST_P(OutputStreamTest, setVolume) {
     doc::test("Try to set the output volume");
-    SKIP_IF_NO_STREAM;
     testOptionalUnitaryGain([this](float volume) { return stream->setVolume(volume, volume); },
                             "setVolume");
 }
 
 static void testPrepareForWriting(IStreamOut* stream, uint32_t frameSize, uint32_t framesCount) {
     Result res;
-    SKIP_IF_NO_STREAM;
     // Ignore output parameters as the call should fail
     ASSERT_OK(stream->prepareForWriting(frameSize, framesCount,
                                         [&res](auto r, auto&, auto&, auto&, auto&) { res = r; }));
@@ -1313,13 +1220,11 @@
 
 TEST_P(OutputStreamTest, PrepareForWriteWithZeroBuffer) {
     doc::test("Preparing a stream for writing with a 0 sized buffer should fail");
-    SKIP_IF_NO_STREAM;
     testPrepareForWriting(stream.get(), 0, 0);
 }
 
 TEST_P(OutputStreamTest, PrepareForWriteWithHugeBuffer) {
     doc::test("Preparing a stream for writing with a 2^32 sized buffer should fail");
-    SKIP_IF_NO_STREAM;
     testPrepareForWriting(stream.get(), 1, std::numeric_limits<uint32_t>::max());
 }
 
@@ -1327,7 +1232,6 @@
     doc::test(
         "Preparing a stream for writing with a overflowing sized buffer should "
         "fail");
-    SKIP_IF_NO_STREAM;
     auto uintMax = std::numeric_limits<uint32_t>::max();
     testPrepareForWriting(stream.get(), uintMax, uintMax);
 }
@@ -1348,7 +1252,6 @@
 
 TEST_P(OutputStreamTest, SupportsPauseAndResumeAndDrain) {
     doc::test("Implementation must expose pause, resume and drain capabilities");
-    SKIP_IF_NO_STREAM;
     Capability(stream.get());
 }
 
@@ -1367,7 +1270,6 @@
 
 TEST_P(OutputStreamTest, GetRenderPosition) {
     doc::test("A new stream render position should be 0 or INVALID_STATE");
-    SKIP_IF_NO_STREAM;
     uint32_t dspFrames;
     ASSERT_OK(stream->getRenderPosition(returnIn(res, dspFrames)));
     if (res == Result::NOT_SUPPORTED) {
@@ -1379,7 +1281,6 @@
 
 TEST_P(OutputStreamTest, GetNextWriteTimestamp) {
     doc::test("A new stream next write timestamp should be 0 or INVALID_STATE");
-    SKIP_IF_NO_STREAM;
     uint64_t timestampUs;
     ASSERT_OK(stream->getNextWriteTimestamp(returnIn(res, timestampUs)));
     if (res == Result::NOT_SUPPORTED) {
@@ -1397,7 +1298,6 @@
 };
 
 static bool isAsyncModeSupported(IStreamOut* stream) {
-    if (!stream) return false;
     auto res = stream->setCallback(new MockOutCallbacks);
     stream->clearCallback();  // try to restore the no callback state, ignore
                               // any error
@@ -1434,7 +1334,6 @@
     doc::test(
         "If supported, a stream should fail to resume if not previously "
         "paused");
-    SKIP_IF_NO_STREAM;
     if (!Capability(stream.get()).resume) {
         doc::partialTest("The output stream does not support resume");
         return;
@@ -1446,7 +1345,6 @@
     doc::test(
         "If supported, a stream should fail to pause if not previously "
         "started");
-    SKIP_IF_NO_STREAM;
     if (!Capability(stream.get()).pause) {
         doc::partialTest("The output stream does not support pause");
         return;
@@ -1464,19 +1362,16 @@
 
 TEST_P(OutputStreamTest, DrainAll) {
     doc::test("If supported, a stream should always succeed to drain");
-    SKIP_IF_NO_STREAM;
     testDrain(stream.get(), AudioDrain::ALL);
 }
 
 TEST_P(OutputStreamTest, DrainEarlyNotify) {
     doc::test("If supported, a stream should always succeed to drain");
-    SKIP_IF_NO_STREAM;
     testDrain(stream.get(), AudioDrain::EARLY_NOTIFY);
 }
 
 TEST_P(OutputStreamTest, FlushStop) {
     doc::test("If supported, a stream should always succeed to flush");
-    SKIP_IF_NO_STREAM;
     auto ret = stream->flush();
     ASSERT_IS_OK(ret);
     if (ret == Result::NOT_SUPPORTED) {
@@ -1490,7 +1385,6 @@
     doc::test(
         "If supported, a stream should always succeed to retrieve the "
         "presentation position");
-    SKIP_IF_NO_STREAM;
     uint64_t frames;
     TimeSpec mesureTS;
     ASSERT_OK(stream->getPresentationPosition(returnIn(res, frames, mesureTS)));
@@ -1518,13 +1412,11 @@
 
 TEST_P(OutputStreamTest, SelectPresentation) {
     doc::test("Verify that presentation selection does not crash");
-    SKIP_IF_NO_STREAM;
     ASSERT_RESULT(okOrNotSupported, stream->selectPresentation(0, 0));
 }
 
 TEST_P(OutputStreamTest, updateSourceMetadata) {
     doc::test("The HAL should not crash on metadata change");
-    SKIP_IF_NO_STREAM;
 
     hidl_enum_iterator<AudioUsage> usageRange;
     hidl_enum_iterator<AudioContentType> contentRange;
@@ -1560,13 +1452,11 @@
 
 TEST_F(AudioPrimaryHidlTest, setVoiceVolume) {
     doc::test("Make sure setVoiceVolume only succeed if volume is in [0,1]");
-    SKIP_IF_NO_DEVICE;
     testUnitaryGain([](float volume) { return device->setVoiceVolume(volume); });
 }
 
 TEST_F(AudioPrimaryHidlTest, setMode) {
     doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise");
-    SKIP_IF_NO_DEVICE;
     // Test Invalid values
     for (int mode : {-2, -1, int(AudioMode::IN_COMMUNICATION) + 1}) {
         ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(AudioMode(mode)))
@@ -1583,7 +1473,6 @@
     doc::test(
         "Make sure setBtHfpSampleRate either succeeds or "
         "indicates that it is not supported at all, or that the provided value is invalid");
-    SKIP_IF_NO_DEVICE;
     for (auto samplingRate : {8000, 16000, 22050, 24000}) {
         ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, device->setBtHfpSampleRate(samplingRate));
     }
@@ -1593,7 +1482,6 @@
     doc::test(
         "Make sure setBtHfpVolume is either not supported or "
         "only succeed if volume is in [0,1]");
-    SKIP_IF_NO_DEVICE;
     auto ret = device->setBtHfpVolume(0.0);
     ASSERT_TRUE(ret.isOk());
     if (ret == Result::NOT_SUPPORTED) {
@@ -1607,13 +1495,11 @@
     doc::test(
         "Make sure setBtScoHeadsetDebugName either succeeds or "
         "indicates that it is not supported");
-    SKIP_IF_NO_DEVICE;
     ASSERT_RESULT(okOrNotSupported, device->setBtScoHeadsetDebugName("test"));
 }
 
 TEST_F(AudioPrimaryHidlTest, updateRotation) {
     doc::test("Check that the hal can receive the current rotation");
-    SKIP_IF_NO_DEVICE;
     for (Rotation rotation : {Rotation::DEG_0, Rotation::DEG_90, Rotation::DEG_180,
                               Rotation::DEG_270, Rotation::DEG_0}) {
         ASSERT_RESULT(okOrNotSupported, device->updateRotation(rotation));
diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp
index 69f8535..fd785df 100644
--- a/camera/device/3.2/default/CameraDeviceSession.cpp
+++ b/camera/device/3.2/default/CameraDeviceSession.cpp
@@ -53,6 +53,7 @@
         camera3_callback_ops({&sProcessCaptureResult, &sNotify}),
         mDevice(device),
         mDeviceVersion(device->common.version),
+        mFreeBufEarly(shouldFreeBufEarly()),
         mIsAELockAvailable(false),
         mDerivePostRawSensKey(false),
         mNumPartialResults(1),
@@ -129,6 +130,10 @@
     return false;
 }
 
+bool CameraDeviceSession::shouldFreeBufEarly() {
+    return property_get_bool("ro.vendor.camera.free_buf_early", 0) == 1;
+}
+
 CameraDeviceSession::~CameraDeviceSession() {
     if (!isClosed()) {
         ALOGE("CameraDeviceSession deleted before close!");
@@ -887,6 +892,24 @@
         (*streams)[i] = &mStreamMap[id];
     }
 
+    if (mFreeBufEarly) {
+        // Remove buffers of deleted streams
+        for(auto it = mStreamMap.begin(); it != mStreamMap.end(); it++) {
+            int id = it->first;
+            bool found = false;
+            for (const auto& stream : requestedConfiguration.streams) {
+                if (id == stream.id) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                // Unmap all buffers of deleted stream
+                cleanupBuffersLocked(id);
+            }
+        }
+    }
+
     return true;
 }
 
@@ -908,7 +931,9 @@
             // Unmap all buffers of deleted stream
             // in case the configuration call succeeds and HAL
             // is able to release the corresponding resources too.
-            cleanupBuffersLocked(id);
+            if (!mFreeBufEarly) {
+                cleanupBuffersLocked(id);
+            }
             it = mStreamMap.erase(it);
         } else {
             ++it;
@@ -927,6 +952,27 @@
     mResultBatcher.setBatchedStreams(mVideoStreamIds);
 }
 
+
+void CameraDeviceSession::postProcessConfigurationFailureLocked(
+        const StreamConfiguration& requestedConfiguration) {
+    if (mFreeBufEarly) {
+        // Re-build the buf cache entry for deleted streams
+        for(auto it = mStreamMap.begin(); it != mStreamMap.end(); it++) {
+            int id = it->first;
+            bool found = false;
+            for (const auto& stream : requestedConfiguration.streams) {
+                if (id == stream.id) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                mCirculatingBuffers.emplace(id, CirculatingBuffers{});
+            }
+        }
+    }
+}
+
 Return<void> CameraDeviceSession::configureStreams(
         const StreamConfiguration& requestedConfiguration,
         ICameraDeviceSession::configureStreams_cb _hidl_cb)  {
@@ -979,6 +1025,8 @@
     // the corresponding resources of the deleted streams.
     if (ret == OK) {
         postProcessConfigurationLocked(requestedConfiguration);
+    } else {
+        postProcessConfigurationFailureLocked(requestedConfiguration);
     }
 
     if (ret == -EINVAL) {
diff --git a/camera/device/3.2/default/CameraDeviceSession.h b/camera/device/3.2/default/CameraDeviceSession.h
index af90e5a..bcee259 100644
--- a/camera/device/3.2/default/CameraDeviceSession.h
+++ b/camera/device/3.2/default/CameraDeviceSession.h
@@ -120,6 +120,8 @@
             hidl_vec<camera3_stream_t*> *streams /*out*/);
     void postProcessConfigurationLocked(const StreamConfiguration& requestedConfiguration);
 
+    void postProcessConfigurationFailureLocked(const StreamConfiguration& requestedConfiguration);
+
 protected:
 
     // protecting mClosed/mDisconnected/mInitFail
@@ -142,6 +144,7 @@
 
     camera3_device_t* mDevice;
     const uint32_t mDeviceVersion;
+    const bool mFreeBufEarly;
     bool mIsAELockAvailable;
     bool mDerivePostRawSensKey;
     uint32_t mNumPartialResults;
@@ -293,6 +296,8 @@
 
     bool initialize();
 
+    static bool shouldFreeBufEarly();
+
     Status initStatus() const;
 
     // Validate and import request's input buffer and acquire fence
diff --git a/camera/device/3.3/default/CameraDeviceSession.cpp b/camera/device/3.3/default/CameraDeviceSession.cpp
index d36e9ed..60174fb 100644
--- a/camera/device/3.3/default/CameraDeviceSession.cpp
+++ b/camera/device/3.3/default/CameraDeviceSession.cpp
@@ -92,6 +92,8 @@
     // the corresponding resources of the deleted streams.
     if (ret == OK) {
         postProcessConfigurationLocked(requestedConfiguration);
+    } else {
+        postProcessConfigurationFailureLocked(requestedConfiguration);
     }
 
     if (ret == -EINVAL) {
diff --git a/camera/device/3.4/default/CameraDeviceSession.cpp b/camera/device/3.4/default/CameraDeviceSession.cpp
index 6a18161..f2e031c 100644
--- a/camera/device/3.4/default/CameraDeviceSession.cpp
+++ b/camera/device/3.4/default/CameraDeviceSession.cpp
@@ -154,6 +154,8 @@
     // the corresponding resources of the deleted streams.
     if (ret == OK) {
         postProcessConfigurationLocked_3_4(requestedConfiguration);
+    } else {
+        postProcessConfigurationFailureLocked_3_4(requestedConfiguration);
     }
 
     if (ret == -EINVAL) {
@@ -215,6 +217,23 @@
         (*streams)[i] = &mStreamMap[id];
     }
 
+    if (mFreeBufEarly) {
+        // Remove buffers of deleted streams
+        for(auto it = mStreamMap.begin(); it != mStreamMap.end(); it++) {
+            int id = it->first;
+            bool found = false;
+            for (const auto& stream : requestedConfiguration.streams) {
+                if (id == stream.v3_2.id) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                // Unmap all buffers of deleted stream
+                cleanupBuffersLocked(id);
+            }
+        }
+    }
     return true;
 }
 
@@ -236,7 +255,9 @@
             // Unmap all buffers of deleted stream
             // in case the configuration call succeeds and HAL
             // is able to release the corresponding resources too.
-            cleanupBuffersLocked(id);
+            if (!mFreeBufEarly) {
+                cleanupBuffersLocked(id);
+            }
             it = mStreamMap.erase(it);
         } else {
             ++it;
@@ -255,6 +276,26 @@
     mResultBatcher_3_4.setBatchedStreams(mVideoStreamIds);
 }
 
+void CameraDeviceSession::postProcessConfigurationFailureLocked_3_4(
+        const StreamConfiguration& requestedConfiguration) {
+    if (mFreeBufEarly) {
+        // Re-build the buf cache entry for deleted streams
+        for(auto it = mStreamMap.begin(); it != mStreamMap.end(); it++) {
+            int id = it->first;
+            bool found = false;
+            for (const auto& stream : requestedConfiguration.streams) {
+                if (id == stream.v3_2.id) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                mCirculatingBuffers.emplace(id, CirculatingBuffers{});
+            }
+        }
+    }
+}
+
 Return<void> CameraDeviceSession::processCaptureRequest_3_4(
         const hidl_vec<V3_4::CaptureRequest>& requests,
         const hidl_vec<V3_2::BufferCache>& cachesToRemove,
diff --git a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
index 5d6a112..fdc8a5a 100644
--- a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
+++ b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
@@ -84,6 +84,8 @@
             camera3_stream_configuration_t *stream_list /*out*/,
             hidl_vec<camera3_stream_t*> *streams /*out*/);
     void postProcessConfigurationLocked_3_4(const StreamConfiguration& requestedConfiguration);
+    void postProcessConfigurationFailureLocked_3_4(
+            const StreamConfiguration& requestedConfiguration);
 
     Return<void> processCaptureRequest_3_4(
             const hidl_vec<V3_4::CaptureRequest>& requests,
diff --git a/drm/1.0/default/CryptoPlugin.cpp b/drm/1.0/default/CryptoPlugin.cpp
index f9c868d..4fe6c9b 100644
--- a/drm/1.0/default/CryptoPlugin.cpp
+++ b/drm/1.0/default/CryptoPlugin.cpp
@@ -102,11 +102,20 @@
         std::unique_ptr<android::CryptoPlugin::SubSample[]> legacySubSamples =
                 std::make_unique<android::CryptoPlugin::SubSample[]>(subSamples.size());
 
+        size_t destSize = 0;
         for (size_t i = 0; i < subSamples.size(); i++) {
-            legacySubSamples[i].mNumBytesOfClearData
-                = subSamples[i].numBytesOfClearData;
-            legacySubSamples[i].mNumBytesOfEncryptedData
-                = subSamples[i].numBytesOfEncryptedData;
+            uint32_t numBytesOfClearData = subSamples[i].numBytesOfClearData;
+            legacySubSamples[i].mNumBytesOfClearData = numBytesOfClearData;
+            uint32_t numBytesOfEncryptedData = subSamples[i].numBytesOfEncryptedData;
+            legacySubSamples[i].mNumBytesOfEncryptedData = numBytesOfEncryptedData;
+            if (__builtin_add_overflow(destSize, numBytesOfClearData, &destSize)) {
+                _hidl_cb(Status::BAD_VALUE, 0, "subsample clear size overflow");
+                return Void();
+            }
+            if (__builtin_add_overflow(destSize, numBytesOfEncryptedData, &destSize)) {
+                _hidl_cb(Status::BAD_VALUE, 0, "subsample encrypted size overflow");
+                return Void();
+            }
         }
 
         AString detailMessage;
@@ -138,11 +147,24 @@
                 _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
                 return Void();
             }
+
+            if (destSize > destBuffer.size) {
+                _hidl_cb(Status::BAD_VALUE, 0, "subsample sum too large");
+                return Void();
+            }
+
             destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
         } else if (destination.type == BufferType::NATIVE_HANDLE) {
+            if (!secure) {
+                _hidl_cb(Status::BAD_VALUE, 0, "native handle destination must be secure");
+                return Void();
+            }
             native_handle_t *handle = const_cast<native_handle_t *>(
                     destination.secureMemory.getNativeHandle());
             destPtr = static_cast<void *>(handle);
+        } else {
+            _hidl_cb(Status::BAD_VALUE, 0, "invalid destination type");
+            return Void();
         }
         ssize_t result = mLegacyPlugin->decrypt(secure, keyId.data(), iv.data(),
                 legacyMode, legacyPattern, srcPtr, legacySubSamples.get(),
diff --git a/drm/1.0/default/DrmFactory.cpp b/drm/1.0/default/DrmFactory.cpp
index 7e5d998..05951d7 100644
--- a/drm/1.0/default/DrmFactory.cpp
+++ b/drm/1.0/default/DrmFactory.cpp
@@ -1,6 +1,6 @@
 /*
  * 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
diff --git a/drm/1.0/default/LegacyPluginPath.cpp b/drm/1.0/default/LegacyPluginPath.cpp
index 369059d..d0a8f90 100644
--- a/drm/1.0/default/LegacyPluginPath.cpp
+++ b/drm/1.0/default/LegacyPluginPath.cpp
@@ -16,6 +16,8 @@
 
 #include "LegacyPluginPath.h"
 
+#include <unistd.h>
+
 #include <cutils/properties.h>
 
 namespace android {
@@ -24,12 +26,16 @@
 namespace V1_0 {
 namespace implementation {
 
+// 64-bit DRM depends on OEM libraries that aren't
+// provided for all devices. If the drm hal service
+// is running as 64-bit use the 64-bit libs, otherwise
+// use the 32-bit libs.
 const char* getDrmPluginPath() {
-    if (property_get_bool("drm.64bit.enabled", false)) {
-        return "/vendor/lib64/mediadrm";
-    } else {
-        return "/vendor/lib/mediadrm";
-    }
+#if defined(__LP64__)
+    return "/vendor/lib64/mediadrm";
+#else
+    return "/vendor/lib/mediadrm";
+#endif
 }
 
 }  // namespace implementation
diff --git a/drm/1.0/default/include/PluginLoader.h b/drm/1.0/default/include/PluginLoader.h
index f387b3c..0c45fb3 100644
--- a/drm/1.0/default/include/PluginLoader.h
+++ b/drm/1.0/default/include/PluginLoader.h
@@ -85,7 +85,10 @@
                 libraries.push(library);
                 T* result = createFactoryFunc();
                 return  result;
-           }
+            } else {
+                ALOGE("Failed to lookup symbol %s in library %s: %s",
+                        entry, path, library->lastError());
+            }
         }
         return NULL;
     }
diff --git a/graphics/composer/2.1/utils/hwc2onfbadapter/HWC2OnFbAdapter.cpp b/graphics/composer/2.1/utils/hwc2onfbadapter/HWC2OnFbAdapter.cpp
index 7c9e651..0f50577 100644
--- a/graphics/composer/2.1/utils/hwc2onfbadapter/HWC2OnFbAdapter.cpp
+++ b/graphics/composer/2.1/utils/hwc2onfbadapter/HWC2OnFbAdapter.cpp
@@ -32,6 +32,8 @@
 #include <log/log.h>
 #include <sync/sync.h>
 
+using namespace HWC2;
+
 namespace android {
 
 namespace {
@@ -629,9 +631,10 @@
     }
 }
 
-void getCapabilitiesHook(hwc2_device_t* /*device*/, uint32_t* outCount,
-                         int32_t* /*outCapabilities*/) {
-    *outCount = 0;
+void getCapabilitiesHook(hwc2_device_t* device, uint32_t* outCount,
+                         int32_t* outCapabilities) {
+    auto& adapter = HWC2OnFbAdapter::cast(device);
+    adapter.getCapabilities(outCount, outCapabilities);
 }
 
 int closeHook(hw_device_t* device) {
@@ -656,6 +659,10 @@
     mFbInfo.xdpi_scaled = int(mFbDevice->xdpi * 1000.0f);
     mFbInfo.ydpi_scaled = int(mFbDevice->ydpi * 1000.0f);
 
+    // Present fences aren't supported, always indicate PresentFenceIsNotReliable
+    // for FB devices
+    mCapabilities.insert(Capability::PresentFenceIsNotReliable);
+
     mVsyncThread.start(0, mFbInfo.vsync_period_ns);
 }
 
@@ -791,6 +798,23 @@
     mVsyncThread.enableCallback(enable);
 }
 
+void HWC2OnFbAdapter::getCapabilities(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;
+    }
+}
+
 int64_t HWC2OnFbAdapter::VsyncThread::now() {
     struct timespec ts;
     clock_gettime(CLOCK_MONOTONIC, &ts);
diff --git a/graphics/composer/2.1/utils/hwc2onfbadapter/include/hwc2onfbadapter/HWC2OnFbAdapter.h b/graphics/composer/2.1/utils/hwc2onfbadapter/include/hwc2onfbadapter/HWC2OnFbAdapter.h
index d6272fd..f1f11ef 100644
--- a/graphics/composer/2.1/utils/hwc2onfbadapter/include/hwc2onfbadapter/HWC2OnFbAdapter.h
+++ b/graphics/composer/2.1/utils/hwc2onfbadapter/include/hwc2onfbadapter/HWC2OnFbAdapter.h
@@ -23,7 +23,11 @@
 #include <thread>
 #include <unordered_set>
 
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
 #include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
 
 struct framebuffer_device_t;
 
@@ -75,6 +79,7 @@
 
     void setVsyncCallback(HWC2_PFN_VSYNC callback, hwc2_callback_data_t data);
     void enableVsync(bool enable);
+    void getCapabilities(uint32_t* outCount, int32_t* outCapabilities);
 
 private:
     framebuffer_device_t* mFbDevice{nullptr};
@@ -90,6 +95,8 @@
 
     buffer_handle_t mBuffer{nullptr};
 
+    std::unordered_set<HWC2::Capability> mCapabilities;
+
     class VsyncThread {
     public:
         static int64_t now();
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
index a41d902..efe6dad 100644
--- 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
@@ -4,3 +4,4 @@
     group graphics drmrpc
     capabilities SYS_NICE
     onrestart restart surfaceflinger
+    writepid /dev/cpuset/system-background/tasks
diff --git a/health/2.0/README b/health/2.0/README
index 11e6a7a..dfd965a 100644
--- a/health/2.0/README
+++ b/health/2.0/README
@@ -6,12 +6,7 @@
 1. If the device does not have a vendor-specific libhealthd AND does not
    implement storage-related APIs, just do the following:
 
-    1.1 (recommended) To remove healthd from the build,
-        PRODUCT_PACKAGES += android.hardware.health@2.0-service.override
-        DEVICE_FRAMEWORK_MANIFEST_FILE += \
-            system/libhidl/vintfdata/manifest_healthd_exclude.xml
-    1.2 To keep healthd in the build,
-        PRODUCT_PACKAGES += android.hardware.health@2.0-service
+    PRODUCT_PACKAGES += android.hardware.health@2.0-service
 
    Otherwise, continue to Step 2.
 
diff --git a/keymaster/4.0/support/Keymaster.cpp b/keymaster/4.0/support/Keymaster.cpp
index 444298b..9325cc0 100644
--- a/keymaster/4.0/support/Keymaster.cpp
+++ b/keymaster/4.0/support/Keymaster.cpp
@@ -164,10 +164,10 @@
                     sharingCheck = curSharingCheck;
                     firstKeymaster = false;
                 }
-                CHECK(curSharingCheck == sharingCheck)
-                    << "HMAC computation failed for " << *keymaster  //
-                    << " Expected: " << sharingCheck                 //
-                    << " got: " << curSharingCheck;
+                if (curSharingCheck != sharingCheck)
+                    LOG(WARNING) << "HMAC computation failed for " << *keymaster  //
+                                 << " Expected: " << sharingCheck                 //
+                                 << " got: " << curSharingCheck;
             });
         CHECK(rc.isOk()) << "Failed to communicate with " << *keymaster
                          << " error: " << rc.description();
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 784ae30..a2b43f0 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -3899,6 +3899,33 @@
 }
 
 /*
+ * AttestationTest.EcAttestationByKeySize
+ *
+ * Verifies that attesting to EC keys works and generates the expected output.
+ */
+TEST_F(AttestationTest, EcAttestationByKeySize) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .EcdsaSigningKey(256)
+                                             .Digest(Digest::SHA_2_256)
+                                             .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+    hidl_vec<hidl_vec<uint8_t>> cert_chain;
+    ASSERT_EQ(ErrorCode::OK,
+              AttestKey(AuthorizationSetBuilder()
+                            .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+                            .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+                        &cert_chain));
+    EXPECT_GE(cert_chain.size(), 2U);
+    EXPECT_TRUE(verify_chain(cert_chain));
+
+    EXPECT_TRUE(verify_attestation_record("challenge", "foo",                     //
+                                          key_characteristics_.softwareEnforced,  //
+                                          key_characteristics_.hardwareEnforced,  //
+                                          SecLevel(), cert_chain[0]));
+}
+
+/*
  * AttestationTest.EcAttestationRequiresAttestationAppId
  *
  * Verifies that attesting to EC keys requires app ID