Merge "Add IScheduleTest for VTS libhwbinder scheduler test" into oc-dev
diff --git a/audio/2.0/default/service.cpp b/audio/2.0/default/service.cpp
index f3a858a..7f28d7d 100644
--- a/audio/2.0/default/service.cpp
+++ b/audio/2.0/default/service.cpp
@@ -50,7 +50,7 @@
     status = registerPassthroughServiceImplementation<IEffectsFactory>();
     LOG_ALWAYS_FATAL_IF(status != OK, "Error while registering audio effects service: %d", status);
     // Soundtrigger and FM radio might be not present.
-    status = registerPassthroughServiceImplementation<ISoundTriggerHw>("sound_trigger.primary");
+    status = registerPassthroughServiceImplementation<ISoundTriggerHw>();
     ALOGE_IF(status != OK, "Error while registering soundtrigger service: %d", status);
     if (useBroadcastRadioFutureFeatures) {
         status = registerPassthroughServiceImplementation<
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index bf16a9b..c4f935b 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -28,6 +28,25 @@
 
 namespace impl {
 
+/*
+ * This property is used for test purpose to generate fake events.
+ *
+ * It has the following format:
+ *
+ * int32Values[0] - command (1 - start fake data generation, 0 - stop)
+ * int32Values[1] - VehicleProperty to which command applies
+ *
+ * For start command, additional data should be provided:
+ *   int64Values[0] - periodic interval in nanoseconds
+ *   floatValues[0] - initial value
+ *   floatValues[1] - dispersion defines min and max range relative to initial value
+ *   floatValues[2] - increment, with every timer tick the value will be incremented by this amount
+ */
+const int32_t kGenerateFakeDataControllingProperty = 0x0666
+        | VehiclePropertyGroup::VENDOR
+        | VehicleArea::GLOBAL
+        | VehiclePropertyType::COMPLEX;
+
 const int32_t kHvacPowerProperties[] = {
     toInt(VehicleProperty::HVAC_FAN_SPEED),
     toInt(VehicleProperty::HVAC_FAN_DIRECTION),
@@ -64,6 +83,24 @@
 
     {
         .config = {
+            .prop = toInt(VehicleProperty::PERF_ODOMETER),
+            .access = VehiclePropertyAccess::READ,
+            .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        },
+        .initialValue = { .floatValues = {0.0f} }
+    },
+
+    {
+        .config = {
+            .prop = toInt(VehicleProperty::ENGINE_RPM),
+            .access = VehiclePropertyAccess::READ,
+            .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+        },
+        .initialValue = { .floatValues = {0.0f} }
+    },
+
+    {
+        .config = {
             .prop = toInt(VehicleProperty::CURRENT_GEAR),
             .access = VehiclePropertyAccess::READ,
             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -284,6 +321,14 @@
             .maxSampleRate = 10,  // 10 Hz, every 100 ms
         },
         .initialValue = { .floatValues = {101.0f} }
+    },
+
+    {
+        .config = {
+            .prop = kGenerateFakeDataControllingProperty,
+            .access = VehiclePropertyAccess::WRITE,
+            .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        },
     }
 };
 
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index 0ac6ada..ea40cc5 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -27,11 +27,18 @@
 
 namespace impl {
 
+enum class FakeDataCommand : int32_t {
+    Stop = 0,
+    Start = 1,
+};
+
 EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore)
     : mPropStore(propStore),
       mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
       mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer,
-                                  this, std::placeholders::_1)) {
+                                  this, std::placeholders::_1)),
+      mFakeValueGenerator(std::bind(&EmulatedVehicleHal::onFakeValueGenerated,
+                                    this, std::placeholders::_1, std::placeholders::_2)) {
 
     for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
         mPropStore->registerProperty(kVehicleProperties[i].config);
@@ -52,6 +59,10 @@
 }
 
 StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
+    if (propValue.prop == kGenerateFakeDataControllingProperty) {
+        return handleGenerateFakeDataRequest(propValue);
+    };
+
     if (mHvacPowerProps.count(propValue.prop)) {
         auto hvacPowerOn = mPropStore->readValueOrNull(toInt(VehicleProperty::HVAC_POWER_ON),
                                                       toInt(VehicleAreaZone::ROW_1));
@@ -176,6 +187,81 @@
     return mPropStore->readAllValues();
 }
 
+StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
+    ALOGI("%s", __func__);
+    const auto& v = request.value;
+    if (v.int32Values.size() < 2) {
+        ALOGE("%s: expected at least 2 elements in int32Values, got: %zu", __func__,
+                v.int32Values.size());
+        return StatusCode::INVALID_ARG;
+    }
+
+    FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);
+    int32_t propId = v.int32Values[1];
+
+    switch (command) {
+        case FakeDataCommand::Start: {
+            if (!v.int64Values.size()) {
+                ALOGE("%s: interval is not provided in int64Values", __func__);
+                return StatusCode::INVALID_ARG;
+            }
+            auto interval = std::chrono::nanoseconds(v.int64Values[0]);
+
+            if (v.floatValues.size() < 3) {
+                ALOGE("%s: expected at least 3 element sin floatValues, got: %zu", __func__,
+                        v.floatValues.size());
+                return StatusCode::INVALID_ARG;
+            }
+            float initialValue = v.floatValues[0];
+            float dispersion = v.floatValues[1];
+            float increment = v.floatValues[2];
+
+            ALOGI("%s, propId: %d, initalValue: %f", __func__, propId, initialValue);
+            mFakeValueGenerator.startGeneratingHalEvents(
+                interval, propId, initialValue, dispersion, increment);
+
+            break;
+        }
+        case FakeDataCommand::Stop: {
+            ALOGI("%s, FakeDataCommandStop", __func__);
+            mFakeValueGenerator.stopGeneratingHalEvents(propId);
+            break;
+        }
+        default: {
+            ALOGE("%s: unexpected command: %d", __func__, command);
+            return StatusCode::INVALID_ARG;
+        }
+    }
+    return StatusCode::OK;
+}
+
+void EmulatedVehicleHal::onFakeValueGenerated(int32_t propId, float value) {
+    VehiclePropValuePtr updatedPropValue {};
+    switch (getPropType(propId)) {
+        case VehiclePropertyType::FLOAT:
+            updatedPropValue = getValuePool()->obtainFloat(value);
+            break;
+        case VehiclePropertyType::INT32:
+            updatedPropValue = getValuePool()->obtainInt32(static_cast<int32_t>(value));
+            break;
+        default:
+            ALOGE("%s: data type for property: 0x%x not supported", __func__, propId);
+            return;
+
+    }
+
+    if (updatedPropValue) {
+        updatedPropValue->prop = propId;
+        updatedPropValue->areaId = 0;  // Add area support if necessary.
+        updatedPropValue->timestamp = elapsedRealtimeNano();
+        mPropStore->writeValue(*updatedPropValue);
+        auto changeMode = mPropStore->getConfigOrDie(propId)->changeMode;
+        if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) {
+            doHalEvent(move(updatedPropValue));
+        }
+    }
+}
+
 }  // impl
 
 }  // namespace V2_0
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index e0874e2..009485d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -34,6 +34,7 @@
 #include "DefaultConfig.h"
 #include "VehicleHalProto.pb.h"
 #include "VehicleEmulator.h"
+#include "FakeValueGenerator.h"
 
 namespace android {
 namespace hardware {
@@ -67,6 +68,9 @@
         return std::chrono::nanoseconds(static_cast<int64_t>(1000000000L / hz));
     }
 
+    StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
+    void onFakeValueGenerated(int32_t propId, float value);
+
     void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
     bool isContinuousProperty(int32_t propId) const;
 
@@ -74,6 +78,7 @@
     VehiclePropertyStore* mPropStore;
     std::unordered_set<int32_t> mHvacPowerProps;
     RecurrentTimer mRecurrentTimer;
+    FakeValueGenerator mFakeValueGenerator;
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h
new file mode 100644
index 0000000..7bbbb08
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h
@@ -0,0 +1,127 @@
+/*
+ * 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 android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_
+
+#include <chrono>
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+#include <vhal_v2_0/RecurrentTimer.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+class FakeValueGenerator {
+private:
+    // In every timer tick we may want to generate new value based on initial value for debug
+    // purpose. It's better to have sequential values to see if events gets delivered in order
+    // to the client.
+
+    struct GeneratorCfg {
+        float initialValue;  //
+        float currentValue;  //  Should be in range (initialValue +/- dispersion).
+        float dispersion;    //  Defines minimum and maximum value based on initial value.
+        float increment;     //  Value that we will be added to currentValue with each timer tick.
+    };
+
+public:
+    using OnHalEvent = std::function<void(int32_t propId, float value)>;
+
+    FakeValueGenerator(const OnHalEvent& onHalEvent) :
+        mOnHalEvent(onHalEvent),
+        mRecurrentTimer(std::bind(&FakeValueGenerator::onTimer, this,
+                                  std::placeholders::_1))
+    {}
+
+    ~FakeValueGenerator() = default;
+
+
+    void startGeneratingHalEvents(std::chrono::nanoseconds interval, int propId, float initialValue,
+                                  float dispersion, float increment) {
+        MuxGuard g(mLock);
+
+        removeLocked(propId);
+
+        mGenCfg.insert({propId, GeneratorCfg {
+            .initialValue = initialValue,
+            .currentValue = initialValue,
+            .dispersion = dispersion,
+            .increment = increment,
+        }});
+
+        mRecurrentTimer.registerRecurrentEvent(interval, propId);
+    }
+
+    void stopGeneratingHalEvents(int propId) {
+        MuxGuard g(mLock);
+        if (propId == 0) {
+            // Remove all.
+            for (auto&& it : mGenCfg) {
+                removeLocked(it.first);
+            }
+        } else {
+            removeLocked(propId);
+        }
+    }
+
+private:
+    void removeLocked(int propId) {
+        if (mGenCfg.erase(propId)) {
+            mRecurrentTimer.unregisterRecurrentEvent(propId);
+        }
+    }
+
+    void onTimer(const std::vector<int32_t>& properties) {
+        MuxGuard g(mLock);
+
+        for (int32_t propId : properties) {
+            auto& cfg = mGenCfg[propId];
+            cfg.currentValue += cfg.increment;
+            if (cfg.currentValue > cfg.initialValue + cfg.dispersion) {
+                cfg.currentValue = cfg.initialValue - cfg.dispersion;
+            }
+            mOnHalEvent(propId, cfg.currentValue);
+        }
+    }
+
+private:
+    using MuxGuard = std::lock_guard<std::mutex>;
+
+    mutable std::mutex mLock;
+    OnHalEvent mOnHalEvent;
+    RecurrentTimer mRecurrentTimer;
+    std::unordered_map<int32_t, GeneratorCfg> mGenCfg;
+};
+
+
+}  // impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+
+
+#endif //android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_
diff --git a/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp b/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp
index 7ba84bd..16197d7 100644
--- a/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp
+++ b/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp
@@ -23,6 +23,7 @@
 #include "BiometricsFingerprint.h"
 
 #include <inttypes.h>
+#include <unistd.h>
 
 namespace android {
 namespace hardware {
@@ -187,7 +188,12 @@
         const hidl_string& storePath) {
     if (storePath.size() >= PATH_MAX || storePath.size() <= 0) {
         ALOGE("Bad path length: %zd", storePath.size());
+        return RequestStatus::SYS_EINVAL;
     }
+    if (access(storePath.c_str(), W_OK)) {
+        return RequestStatus::SYS_EINVAL;
+    }
+
     return ErrorFilter(mDevice->set_active_group(mDevice, gid,
                                                     storePath.c_str()));
 }
diff --git a/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
index d3f6612..29776b4 100644
--- a/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
+++ b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
@@ -43,7 +43,7 @@
 static const uint32_t kTimeout = 3;
 static const std::chrono::seconds kTimeoutInSeconds = std::chrono::seconds(kTimeout);
 static const uint32_t kGroupId = 99;
-static const std::string kTmpDir = "/data/local/tmp/";
+static const std::string kTmpDir = "/data/system/";
 static const uint32_t kIterations = 1000;
 
 // Wait for a callback to occur (signaled by the given future) up to the
@@ -186,6 +186,8 @@
     ASSERT_FALSE(mService == nullptr);
 
     // Create an active group
+    // FP service can only write to /data/system due to
+    // SELinux Policy and Linux Dir Permissions
     Return<RequestStatus> res = mService->setActiveGroup(kGroupId, kTmpDir);
     ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
   }
diff --git a/bluetooth/1.0/default/Android.mk b/bluetooth/1.0/default/Android.mk
index 7530925..38294c7 100644
--- a/bluetooth/1.0/default/Android.mk
+++ b/bluetooth/1.0/default/Android.mk
@@ -29,7 +29,6 @@
   libdl \
   libbase \
   libutils \
-  libhardware_legacy \
   libhardware \
 
 LOCAL_SHARED_LIBRARIES += \
diff --git a/camera/device/3.2/ICameraDeviceCallback.hal b/camera/device/3.2/ICameraDeviceCallback.hal
index bf51da2..69715de 100644
--- a/camera/device/3.2/ICameraDeviceCallback.hal
+++ b/camera/device/3.2/ICameraDeviceCallback.hal
@@ -42,7 +42,9 @@
      * metadata and low-resolution buffers to be returned in one call, and
      * post-processed JPEG buffers in a later call, once it is available. Each
      * call must include the frame number of the request it is returning
-     * metadata or buffers for.
+     * metadata or buffers for. Only one call to processCaptureResult
+     * may be made at a time by the HAL although the calls may come from
+     * different threads in the HAL.
      *
      * A component (buffer or metadata) of the complete result may only be
      * included in one process_capture_result call. A buffer for each stream,
diff --git a/camera/device/3.2/ICameraDeviceSession.hal b/camera/device/3.2/ICameraDeviceSession.hal
index bf56881..477a3cc 100644
--- a/camera/device/3.2/ICameraDeviceSession.hal
+++ b/camera/device/3.2/ICameraDeviceSession.hal
@@ -263,6 +263,24 @@
     getCaptureRequestMetadataQueue() generates (fmq_sync<uint8_t> queue);
 
     /**
+     * getCaptureResultMetadataQueue:
+     *
+     * Retrieves the queue used along with
+     * ICameraDeviceCallback.processCaptureResult.
+     *
+     * Clients to ICameraDeviceSession must:
+     * - Call getCaptureRequestMetadataQueue to retrieve the fast message queue;
+     * - In implementation of ICameraDeviceCallback, test whether
+     *   .fmqResultSize field is zero.
+     *     - If .fmqResultSize != 0, read result metadata from the fast message
+     *       queue;
+     *     - otherwise, read result metadata in CaptureResult.result.
+     *
+     * @return queue the queue that implementation writes result metadata to.
+     */
+    getCaptureResultMetadataQueue() generates (fmq_sync<uint8_t> queue);
+
+    /**
      * flush:
      *
      * Flush all currently in-process captures and all buffers in the pipeline
diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp
index ebb8fcb..2499b1a 100644
--- a/camera/device/3.2/default/CameraDeviceSession.cpp
+++ b/camera/device/3.2/default/CameraDeviceSession.cpp
@@ -32,6 +32,8 @@
 
 // Size of request metadata fast message queue. Change to 0 to always use hwbinder buffer.
 static constexpr size_t CAMERA_REQUEST_METADATA_QUEUE_SIZE = 1 << 20 /* 1MB */;
+// Size of result metadata fast message queue. Change to 0 to always use hwbinder buffer.
+static constexpr size_t CAMERA_RESULT_METADATA_QUEUE_SIZE  = 1 << 20 /* 1MB */;
 
 HandleImporter& CameraDeviceSession::sHandleImporter = HandleImporter::getInstance();
 const int CameraDeviceSession::ResultBatcher::NOT_BATCHED;
@@ -73,9 +75,16 @@
     mRequestMetadataQueue = std::make_unique<RequestMetadataQueue>(
             CAMERA_REQUEST_METADATA_QUEUE_SIZE, false /* non blocking */);
     if (!mRequestMetadataQueue->isValid()) {
-        ALOGE("%s: invalid fmq", __FUNCTION__);
+        ALOGE("%s: invalid request fmq", __FUNCTION__);
         return true;
     }
+    mResultMetadataQueue = std::make_shared<RequestMetadataQueue>(
+            CAMERA_RESULT_METADATA_QUEUE_SIZE, false /* non blocking */);
+    if (!mResultMetadataQueue->isValid()) {
+        ALOGE("%s: invalid result fmq", __FUNCTION__);
+        return true;
+    }
+    mResultBatcher.setResultMetadataQueue(mResultMetadataQueue);
 
     return false;
 }
@@ -231,6 +240,11 @@
     mStreamsToBatch = streamsToBatch;
 }
 
+void CameraDeviceSession::ResultBatcher::setResultMetadataQueue(std::shared_ptr<ResultMetadataQueue> q) {
+    Mutex::Autolock _l(mLock);
+    mResultMetadataQueue = q;
+}
+
 void CameraDeviceSession::ResultBatcher::registerBatch(
         const hidl_vec<CaptureRequest>& requests) {
     auto batch = std::make_shared<InflightBatch>();
@@ -350,6 +364,7 @@
     results.resize(batchSize);
     for (size_t i = 0; i < batchSize; i++) {
         results[i].frameNumber = batch->mFirstFrame + i;
+        results[i].fmqResultSize = 0;
         results[i].partialResult = 0; // 0 for buffer only results
         results[i].inputBuffer.streamId = -1;
         results[i].inputBuffer.bufferId = 0;
@@ -366,7 +381,7 @@
         }
         results[i].outputBuffers = outBufs;
     }
-    mCallback->processCaptureResult(results);
+    invokeProcessCaptureResultCallback(results, /* tryWriteFmq */false);
     freeReleaseFences(results);
     for (int streamId : streams) {
         InflightBatch::BufferBatch& bb = batch->mBatchBufs[streamId];
@@ -396,6 +411,7 @@
             CaptureResult result;
             result.frameNumber = p.first;
             result.result = std::move(p.second);
+            result.fmqResultSize = 0;
             result.inputBuffer.streamId = -1;
             result.inputBuffer.bufferId = 0;
             result.inputBuffer.buffer = nullptr;
@@ -404,7 +420,9 @@
         }
         mb.mMds.clear();
     }
-    mCallback->processCaptureResult(results);
+    hidl_vec<CaptureResult> hResults;
+    hResults.setToExternal(results.data(), results.size());
+    invokeProcessCaptureResultCallback(hResults, /* tryWriteFmq */true);
     batch->mPartialResultProgress = lastPartialResultIdx;
     for (uint32_t partialIdx : toBeRemovedIdxes) {
         batch->mResultMds.erase(partialIdx);
@@ -477,9 +495,37 @@
     }
 }
 
+void CameraDeviceSession::ResultBatcher::invokeProcessCaptureResultCallback(
+        hidl_vec<CaptureResult> &results, bool tryWriteFmq) {
+    if (mProcessCaptureResultLock.tryLock() != OK) {
+        ALOGW("%s: previous call is not finished! waiting 1s...",
+                __FUNCTION__);
+        if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
+            ALOGE("%s: cannot acquire lock in 1s, cannot proceed",
+                    __FUNCTION__);
+            return;
+        }
+    }
+    if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) {
+        for (CaptureResult &result : results) {
+            if (result.result.size() > 0) {
+                if (mResultMetadataQueue->write(result.result.data(), result.result.size())) {
+                    result.fmqResultSize = result.result.size();
+                    result.result.resize(0);
+                } else {
+                    ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+                    result.fmqResultSize = 0;
+                }
+            }
+        }
+    }
+    mCallback->processCaptureResult(results);
+    mProcessCaptureResultLock.unlock();
+}
+
 void CameraDeviceSession::ResultBatcher::processOneCaptureResult(CaptureResult& result) {
     hidl_vec<CaptureResult> results = {result};
-    mCallback->processCaptureResult(results);
+    invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
     freeReleaseFences(results);
     return;
 }
@@ -526,6 +572,7 @@
         if (nonBatchedBuffers.size() > 0 || result.inputBuffer.streamId != -1) {
             CaptureResult nonBatchedResult;
             nonBatchedResult.frameNumber = result.frameNumber;
+            nonBatchedResult.fmqResultSize = 0;
             nonBatchedResult.outputBuffers = nonBatchedBuffers;
             nonBatchedResult.inputBuffer = result.inputBuffer;
             nonBatchedResult.partialResult = 0; // 0 for buffer only results
@@ -716,6 +763,12 @@
     return Void();
 }
 
+Return<void> CameraDeviceSession::getCaptureResultMetadataQueue(
+    getCaptureResultMetadataQueue_cb _hidl_cb) {
+    _hidl_cb(*mResultMetadataQueue->getDesc());
+    return Void();
+}
+
 Return<void> CameraDeviceSession::processCaptureRequest(
         const hidl_vec<CaptureRequest>& requests,
         const hidl_vec<BufferCache>& cachesToRemove,
@@ -915,6 +968,7 @@
     // within the scope of this function
     CaptureResult result;
     result.frameNumber = frameNumber;
+    result.fmqResultSize = 0;
     result.partialResult = hal_result->partial_result;
     convertToHidl(hal_result->result, &result.result);
     if (hasInputBuf) {
diff --git a/camera/device/3.2/default/CameraDeviceSession.h b/camera/device/3.2/default/CameraDeviceSession.h
index f59f503..7682165 100644
--- a/camera/device/3.2/default/CameraDeviceSession.h
+++ b/camera/device/3.2/default/CameraDeviceSession.h
@@ -90,6 +90,8 @@
             const StreamConfiguration& requestedConfiguration, configureStreams_cb _hidl_cb) override;
     Return<void> getCaptureRequestMetadataQueue(
         getCaptureRequestMetadataQueue_cb _hidl_cb) override;
+    Return<void> getCaptureResultMetadataQueue(
+        getCaptureResultMetadataQueue_cb _hidl_cb) override;
     Return<void> processCaptureRequest(
             const hidl_vec<CaptureRequest>& requests,
             const hidl_vec<BufferCache>& cachesToRemove,
@@ -134,12 +136,15 @@
 
     using RequestMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
     std::unique_ptr<RequestMetadataQueue> mRequestMetadataQueue;
+    using ResultMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+    std::shared_ptr<ResultMetadataQueue> mResultMetadataQueue;
 
     class ResultBatcher {
     public:
         ResultBatcher(const sp<ICameraDeviceCallback>& callback);
         void setNumPartialResults(uint32_t n);
         void setBatchedStreams(const std::vector<int>& streamsToBatch);
+        void setResultMetadataQueue(std::shared_ptr<ResultMetadataQueue> q);
 
         void registerBatch(const hidl_vec<CaptureRequest>& requests);
         void notify(NotifyMsg& msg);
@@ -217,6 +222,7 @@
         void freeReleaseFences(hidl_vec<CaptureResult>&);
         void notifySingleMsg(NotifyMsg& msg);
         void processOneCaptureResult(CaptureResult& result);
+        void invokeProcessCaptureResultCallback(hidl_vec<CaptureResult> &results, bool tryWriteFmq);
 
         // Protect access to mInflightBatches, mNumPartialResults and mStreamsToBatch
         // processCaptureRequest, processCaptureResult, notify will compete for this lock
@@ -226,6 +232,11 @@
         uint32_t mNumPartialResults;
         std::vector<int> mStreamsToBatch;
         const sp<ICameraDeviceCallback> mCallback;
+        std::shared_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+        // Protect against invokeProcessCaptureResultCallback()
+        Mutex mProcessCaptureResultLock;
+
     } mResultBatcher;
 
     std::vector<int> mVideoStreamIds;
diff --git a/camera/device/3.2/types.hal b/camera/device/3.2/types.hal
index 8e433f6..276e92a 100644
--- a/camera/device/3.2/types.hal
+++ b/camera/device/3.2/types.hal
@@ -853,6 +853,13 @@
     uint32_t frameNumber;
 
     /**
+     * If non-zero, read result from result queue instead
+     * (see ICameraDeviceSession.getCaptureResultMetadataQueue).
+     * If zero, read result from .result field.
+     */
+    uint64_t fmqResultSize;
+
+    /**
      * The result metadata for this capture. This contains information about the
      * final capture parameters, the state of the capture and post-processing
      * hardware, the state of the 3A algorithms, if enabled, and the output of
diff --git a/contexthub/1.0/default/Android.mk b/contexthub/1.0/default/Android.mk
index 538a6b2..917bfe0 100644
--- a/contexthub/1.0/default/Android.mk
+++ b/contexthub/1.0/default/Android.mk
@@ -13,7 +13,6 @@
         libcutils \
         libdl \
         libhardware \
-        libhardware_legacy \
         libhidlbase \
         libhidltransport \
         liblog \
diff --git a/drm/1.0/default/Android.mk b/drm/1.0/default/Android.mk
index 23a4506..7602399 100644
--- a/drm/1.0/default/Android.mk
+++ b/drm/1.0/default/Android.mk
@@ -34,6 +34,7 @@
   libhardware \
   liblog \
   libutils \
+  libbinder \
 
 LOCAL_C_INCLUDES := \
   hardware/interfaces/drm
diff --git a/drm/1.0/default/service.cpp b/drm/1.0/default/service.cpp
index 823f39e..1a44ce2 100644
--- a/drm/1.0/default/service.cpp
+++ b/drm/1.0/default/service.cpp
@@ -21,6 +21,8 @@
 #include <hidl/HidlTransportSupport.h>
 #include <hidl/LegacySupport.h>
 
+#include <binder/ProcessState.h>
+
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
 using android::hardware::registerPassthroughServiceImplementation;
@@ -30,6 +32,11 @@
 
 int main() {
     ALOGD("android.hardware.drm@1.0-service starting...");
+
+    // The DRM HAL may communicate to other vendor components via
+    // /dev/vndbinder
+    android::ProcessState::initWithDriver("/dev/vndbinder");
+
     configureRpcThreadpool(8, true /* callerWillJoin */);
     android::status_t status =
         registerPassthroughServiceImplementation<IDrmFactory>();
diff --git a/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp b/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp
index 4dd98ce..71b893a 100644
--- a/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp
+++ b/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp
@@ -245,6 +245,7 @@
 
     SessionId openSession();
     void closeSession(const SessionId& sessionId);
+    hidl_vec<uint8_t> loadKeys(const SessionId& sessionId, const KeyType& type);
     sp<IMemory> getDecryptMemory(size_t size, size_t index);
 
    protected:
@@ -313,6 +314,70 @@
 }
 
 /**
+ * Helper method to load keys for subsequent decrypt tests.
+ * These tests use predetermined key request/response to
+ * avoid requiring a round trip to a license server.
+ */
+hidl_vec<uint8_t> DrmHalClearkeyPluginTest::loadKeys(
+    const SessionId& sessionId, const KeyType& type = KeyType::STREAMING) {
+    hidl_vec<uint8_t> initData = {
+        // BMFF box header (4 bytes size + 'pssh')
+        0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68,
+        // full box header (version = 1 flags = 0)
+        0x01, 0x00, 0x00, 0x00,
+        // system id
+        0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e,
+        0x52, 0xe2, 0xfb, 0x4b,
+        // number of key ids
+        0x00, 0x00, 0x00, 0x01,
+        // key id
+        0x60, 0x06, 0x1e, 0x01, 0x7e, 0x47, 0x7e, 0x87, 0x7e, 0x57, 0xd0, 0x0d,
+        0x1e, 0xd0, 0x0d, 0x1e,
+        // size of data, must be zero
+        0x00, 0x00, 0x00, 0x00};
+
+    hidl_vec<uint8_t> expectedKeyRequest = {
+        0x7b, 0x22, 0x6b, 0x69, 0x64, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x59,
+        0x41, 0x59, 0x65, 0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2b,
+        0x56, 0x39, 0x41, 0x4e, 0x48, 0x74, 0x41, 0x4e, 0x48, 0x67, 0x22,
+        0x5d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x74,
+        0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x22, 0x7d};
+
+    hidl_vec<uint8_t> knownKeyResponse = {
+        0x7b, 0x22, 0x6b, 0x65, 0x79, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22,
+        0x6b, 0x74, 0x79, 0x22, 0x3a, 0x22, 0x6f, 0x63, 0x74, 0x22, 0x2c,
+        0x22, 0x6b, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x59, 0x41, 0x59, 0x65,
+        0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2b, 0x56, 0x39, 0x41,
+        0x4e, 0x48, 0x74, 0x41, 0x4e, 0x48, 0x67, 0x22, 0x2c, 0x22, 0x6b,
+        0x22, 0x3a, 0x22, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x54, 0x65,
+        0x73, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x61, 0x73, 0x65, 0x36, 0x34,
+        0x67, 0x67, 0x67, 0x22, 0x7d, 0x5d, 0x7d, 0x0a};
+
+    hidl_string mimeType = "video/mp4";
+    KeyedVector optionalParameters;
+    auto res = drmPlugin->getKeyRequest(
+        sessionId, initData, mimeType, type, optionalParameters,
+        [&](Status status, const hidl_vec<uint8_t>& request,
+            KeyRequestType requestType, const hidl_string&) {
+            EXPECT_EQ(Status::OK, status);
+            EXPECT_EQ(KeyRequestType::INITIAL, requestType);
+            EXPECT_EQ(request, expectedKeyRequest);
+        });
+    EXPECT_OK(res);
+
+    hidl_vec<uint8_t> keySetId;
+    res = drmPlugin->provideKeyResponse(
+        sessionId, knownKeyResponse,
+        [&](Status status, const hidl_vec<uint8_t>& myKeySetId) {
+            EXPECT_EQ(Status::OK, status);
+            EXPECT_EQ(0u, myKeySetId.size());
+            keySetId = myKeySetId;
+        });
+    EXPECT_OK(res);
+    return keySetId;
+}
+
+/**
  * Test that a session can be opened and closed
  */
 TEST_F(DrmHalClearkeyPluginTest, OpenCloseSession) {
@@ -471,6 +536,30 @@
 }
 
 /**
+ * Test that ClearKey cannot handle key restoring.
+ * Expected message is Status::ERROR_DRM_CANNOT_HANDLE.
+ */
+TEST_F(DrmHalClearkeyPluginTest, RestoreKeysCannotHandle) {
+    hidl_vec<uint8_t> keySetId = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+    SessionId sessionId = openSession();
+    Status status = drmPlugin->restoreKeys(sessionId, keySetId);
+    EXPECT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status);
+    closeSession(sessionId);
+}
+
+/**
+ * Test that restoreKeys fails with a null key set ID.
+ * Error message is expected to be Status::BAD_VALUE.
+ */
+TEST_F(DrmHalClearkeyPluginTest, RestoreKeysNull) {
+    SessionId sessionId = openSession();
+    hidl_vec<uint8_t> nullKeySetId;
+    Status status = drmPlugin->restoreKeys(sessionId, nullKeySetId);
+    EXPECT_EQ(Status::BAD_VALUE, status);
+    closeSession(sessionId);
+}
+
+/**
  * Test that the clearkey plugin doesn't support getting
  * secure stops.
  */
@@ -831,7 +920,6 @@
 
 class DrmHalClearkeyDecryptTest : public DrmHalClearkeyPluginTest {
    public:
-    void loadKeys(const SessionId& sessionId);
     void fillRandom(const sp<IMemory>& memory);
     hidl_array<uint8_t, 16> toHidlArray(const vector<uint8_t>& vec) {
         EXPECT_EQ(16u, vec.size());
@@ -845,67 +933,6 @@
             const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
 };
 
-/**
- * Helper method to load keys for subsequent decrypt tests.
- * These tests use predetermined key request/response to
- * avoid requiring a round trip to a license server.
- */
-void DrmHalClearkeyDecryptTest::loadKeys(const SessionId& sessionId) {
-    hidl_vec<uint8_t> initData = {
-            // BMFF box header (4 bytes size + 'pssh')
-            0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68,
-            // full box header (version = 1 flags = 0)
-            0x01, 0x00, 0x00, 0x00,
-            // system id
-            0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c,
-            0x1e, 0x52, 0xe2, 0xfb, 0x4b,
-            // number of key ids
-            0x00, 0x00, 0x00, 0x01,
-            // key id
-            0x60, 0x06, 0x1e, 0x01, 0x7e, 0x47, 0x7e, 0x87, 0x7e, 0x57, 0xd0,
-            0x0d, 0x1e, 0xd0, 0x0d, 0x1e,
-            // size of data, must be zero
-            0x00, 0x00, 0x00, 0x00};
-
-    hidl_vec<uint8_t> expectedKeyRequest = {
-            0x7b, 0x22, 0x6b, 0x69, 0x64, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x59,
-            0x41, 0x59, 0x65, 0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2b,
-            0x56, 0x39, 0x41, 0x4e, 0x48, 0x74, 0x41, 0x4e, 0x48, 0x67, 0x22,
-            0x5d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x74,
-            0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x22, 0x7d};
-
-    hidl_vec<uint8_t> knownKeyResponse = {
-            0x7b, 0x22, 0x6b, 0x65, 0x79, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22,
-            0x6b, 0x74, 0x79, 0x22, 0x3a, 0x22, 0x6f, 0x63, 0x74, 0x22, 0x2c,
-            0x22, 0x6b, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x59, 0x41, 0x59, 0x65,
-            0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2b, 0x56, 0x39, 0x41,
-            0x4e, 0x48, 0x74, 0x41, 0x4e, 0x48, 0x67, 0x22, 0x2c, 0x22, 0x6b,
-            0x22, 0x3a, 0x22, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x54, 0x65,
-            0x73, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x61, 0x73, 0x65, 0x36, 0x34,
-            0x67, 0x67, 0x67, 0x22, 0x7d, 0x5d, 0x7d, 0x0a};
-
-    hidl_string mimeType = "video/mp4";
-    KeyedVector optionalParameters;
-    auto res = drmPlugin->getKeyRequest(
-            sessionId, initData, mimeType, KeyType::STREAMING,
-            optionalParameters,
-            [&](Status status, const hidl_vec<uint8_t>& request,
-                KeyRequestType requestType, const hidl_string&) {
-                EXPECT_EQ(Status::OK, status);
-                EXPECT_EQ(KeyRequestType::INITIAL, requestType);
-                EXPECT_EQ(request, expectedKeyRequest);
-            });
-    EXPECT_OK(res);
-
-    res = drmPlugin->provideKeyResponse(
-            sessionId, knownKeyResponse,
-            [&](Status status, const hidl_vec<uint8_t>& keySetId) {
-                EXPECT_EQ(Status::OK, status);
-                EXPECT_EQ(0u, keySetId.size());
-            });
-    EXPECT_OK(res);
-}
-
 void DrmHalClearkeyDecryptTest::fillRandom(const sp<IMemory>& memory) {
     random_device rd;
     mt19937 rand(rd());
diff --git a/drm/1.0/vts/functional/drm_hal_vendor_module_api.h b/drm/1.0/vts/functional/drm_hal_vendor_module_api.h
index 73e0cfe..b8b2052 100644
--- a/drm/1.0/vts/functional/drm_hal_vendor_module_api.h
+++ b/drm/1.0/vts/functional/drm_hal_vendor_module_api.h
@@ -65,7 +65,7 @@
 
 class DrmHalVTSVendorModule {
    public:
-    DrmHalVTSVendorModule() {}
+    DrmHalVTSVendorModule() : installed(true) {}
     virtual ~DrmHalVTSVendorModule() {}
 
     /**
@@ -89,7 +89,15 @@
      */
     virtual std::string getServiceName() const = 0;
 
+    /**
+     * Set a flag in the vendor module to indicate whether or not the drm
+     * scheme corresponding to this module is installed on the device.
+     */
+    void setInstalled(bool flag) {installed = flag;}
+    bool isInstalled() const {return installed;}
+
    private:
+    bool installed;
     DrmHalVTSVendorModule(const DrmHalVTSVendorModule&) = delete;
     void operator=(const DrmHalVTSVendorModule&) = delete;
 };
@@ -158,17 +166,30 @@
         const std::map<std::string, std::string> optionalParameters;
 
         /**
+         *  Define license policy attributes for the content configuration.
+         *  These attributes can affect which tests are able to be applied.
+         */
+        struct Policy {
+            /**
+             * Indicate if the license policy allows offline playback.
+             * Content configurated with this policy supports KeyType::OFFLINE
+             * key requests/responses. A vendor module should provide at least
+             * one content configuration where allowOffline is true if the drm
+             * scheme supports offline content.
+             */
+            bool allowOffline;
+        } policy;
+
+        /**
          * The keys that will be available once the keys are loaded
          */
         struct Key {
             /**
              * Indicate if the key content is configured to require secure
-             * buffers,
-             * where the output buffers are protected and cannot be accessed.
-             * A vendor module should provide some content configurations where
-             * isSecure is false, to allow decrypt result verification tests to
-             * be
-             * run.
+             * buffers, where the output buffers are protected and cannot be
+             * accessed by the non-secure cpu. A vendor module should provide
+             * at least one content configurations where isSecure is false, to
+             * allow decrypt result verification tests to be run.
              */
             bool isSecure;
 
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 fec43cf..ec73a7d 100644
--- a/drm/1.0/vts/functional/drm_hal_vendor_test.cpp
+++ b/drm/1.0/vts/functional/drm_hal_vendor_test.cpp
@@ -83,6 +83,14 @@
 #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
 #define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
 
+#define RETURN_IF_SKIPPED \
+    if (!vendorModule->isInstalled()) { \
+        std::cout << "[  SKIPPED ] This drm scheme not supported." << \
+                " library:" << GetParam() << " service-name:" << \
+                vendorModule->getServiceName() << std::endl; \
+        return; \
+    }
+
 static const uint8_t kInvalidUUID[16] = {
         0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
         0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
@@ -124,6 +132,12 @@
             VtsTestBase::getService<ICryptoFactory>();
         }
         ASSERT_NE(cryptoFactory, nullptr);
+
+        // If drm scheme not installed skip subsequent tests
+        if (!drmFactory->isCryptoSchemeSupported(getVendorUUID())) {
+            vendorModule->setInstalled(false);
+            return;
+        }
     }
 
     virtual void TearDown() override {}
@@ -142,6 +156,7 @@
 
 TEST_P(DrmHalVendorFactoryTest, ValidateConfigurations) {
     const char* kVendorStr = "Vendor module ";
+    size_t count = 0;
     for (auto config : contentConfigurations) {
         ASSERT_TRUE(config.name.size() > 0) << kVendorStr << "has no name";
         ASSERT_TRUE(config.serverUrl.size() > 0) << kVendorStr
@@ -157,7 +172,9 @@
             ASSERT_TRUE(key.keyId.size() > 0) << kVendorStr
                                               << " has zero length key value";
         }
+        count++;
     }
+    EXPECT_NE(0u, count);
 }
 
 /**
@@ -178,9 +195,10 @@
 }
 
 /**
- * Ensure the factory supports the scheme uuid in the config
+ * Check if the factory supports the scheme uuid in the config.
  */
-TEST_P(DrmHalVendorFactoryTest, EmptyPluginConfigUUIDSupported) {
+TEST_P(DrmHalVendorFactoryTest, PluginConfigUUIDSupported) {
+    RETURN_IF_SKIPPED;
     EXPECT_TRUE(drmFactory->isCryptoSchemeSupported(getVendorUUID()));
     EXPECT_TRUE(cryptoFactory->isCryptoSchemeSupported(getVendorUUID()));
 }
@@ -205,6 +223,7 @@
  * Ensure valid content types in the configs are supported
  */
 TEST_P(DrmHalVendorFactoryTest, ValidContentTypeSupported) {
+    RETURN_IF_SKIPPED;
     for (auto config : contentConfigurations) {
         EXPECT_TRUE(drmFactory->isContentTypeSupported(config.mimeType));
     }
@@ -214,6 +233,7 @@
  * Ensure vendor drm plugin can be created
  */
 TEST_P(DrmHalVendorFactoryTest, CreateVendorDrmPlugin) {
+    RETURN_IF_SKIPPED;
     hidl_string packageName("android.hardware.drm.test");
     auto res = drmFactory->createPlugin(
             getVendorUUID(), packageName,
@@ -228,6 +248,7 @@
  * Ensure vendor crypto plugin can be created
  */
 TEST_P(DrmHalVendorFactoryTest, CreateVendorCryptoPlugin) {
+    RETURN_IF_SKIPPED;
     hidl_vec<uint8_t> initVec;
     auto res = cryptoFactory->createPlugin(
             getVendorUUID(), initVec,
@@ -242,6 +263,7 @@
  * Ensure invalid drm plugin can't be created
  */
 TEST_P(DrmHalVendorFactoryTest, CreateInvalidDrmPlugin) {
+    RETURN_IF_SKIPPED;
     hidl_string packageName("android.hardware.drm.test");
     auto res = drmFactory->createPlugin(
             kInvalidUUID, packageName,
@@ -256,6 +278,7 @@
  * Ensure invalid crypto plugin can't be created
  */
 TEST_P(DrmHalVendorFactoryTest, CreateInvalidCryptoPlugin) {
+    RETURN_IF_SKIPPED;
     hidl_vec<uint8_t> initVec;
     auto res = cryptoFactory->createPlugin(
             kInvalidUUID, initVec,
@@ -272,6 +295,7 @@
     virtual void SetUp() override {
         // Create factories
         DrmHalVendorFactoryTest::SetUp();
+        RETURN_IF_SKIPPED;
 
         hidl_string packageName("android.hardware.drm.test");
         auto res = drmFactory->createPlugin(
@@ -299,6 +323,10 @@
     SessionId openSession();
     void closeSession(const SessionId& sessionId);
     sp<IMemory> getDecryptMemory(size_t size, size_t index);
+    KeyedVector toHidlKeyedVector(const map<string, string>& params);
+    hidl_vec<uint8_t> loadKeys(const SessionId& sessionId,
+                               const ContentConfiguration& configuration,
+                               const KeyType& type);
 
    protected:
     sp<IDrmPlugin> drmPlugin;
@@ -319,6 +347,7 @@
  */
 
 TEST_P(DrmHalVendorPluginTest, DoProvisioning) {
+    RETURN_IF_SKIPPED;
     hidl_string certificateType;
     hidl_string certificateAuthority;
     hidl_vec<uint8_t> provisionRequest;
@@ -356,6 +385,7 @@
  * response is provided.
  */
 TEST_P(DrmHalVendorPluginTest, ProvideEmptyProvisionResponse) {
+    RETURN_IF_SKIPPED;
     hidl_vec<uint8_t> response;
     auto res = drmPlugin->provideProvisionResponse(
             response, [&](Status status, const hidl_vec<uint8_t>&,
@@ -389,10 +419,69 @@
     EXPECT_EQ(Status::OK, status);
 }
 
+KeyedVector DrmHalVendorPluginTest::toHidlKeyedVector(
+    const map<string, string>& params) {
+    std::vector<KeyValue> stdKeyedVector;
+    for (auto it = params.begin(); it != params.end(); ++it) {
+        KeyValue keyValue;
+        keyValue.key = it->first;
+        keyValue.value = it->second;
+        stdKeyedVector.push_back(keyValue);
+    }
+    return KeyedVector(stdKeyedVector);
+}
+
+/**
+ * Helper method to load keys for subsequent decrypt tests.
+ * These tests use predetermined key request/response to
+ * avoid requiring a round trip to a license server.
+ */
+hidl_vec<uint8_t> DrmHalVendorPluginTest::loadKeys(
+    const SessionId& sessionId, const ContentConfiguration& configuration,
+    const KeyType& type = KeyType::STREAMING) {
+    hidl_vec<uint8_t> keyRequest;
+    auto res = drmPlugin->getKeyRequest(
+        sessionId, configuration.initData, configuration.mimeType, type,
+        toHidlKeyedVector(configuration.optionalParameters),
+        [&](Status status, const hidl_vec<uint8_t>& request,
+            KeyRequestType type, const hidl_string&) {
+            EXPECT_EQ(Status::OK, status) << "Failed to get "
+                                             "key request for configuration "
+                                          << configuration.name;
+            EXPECT_EQ(type, KeyRequestType::INITIAL);
+            EXPECT_NE(request.size(), 0u) << "Expected key request size"
+                                             " to have length > 0 bytes";
+            keyRequest = request;
+        });
+    EXPECT_OK(res);
+
+    /**
+     * Get key response from vendor module
+     */
+    hidl_vec<uint8_t> keyResponse =
+        vendorModule->handleKeyRequest(keyRequest, configuration.serverUrl);
+
+    EXPECT_NE(keyResponse.size(), 0u) << "Expected key response size "
+                                         "to have length > 0 bytes";
+
+    hidl_vec<uint8_t> keySetId;
+    res = drmPlugin->provideKeyResponse(
+        sessionId, keyResponse,
+        [&](Status status, const hidl_vec<uint8_t>& myKeySetId) {
+            EXPECT_EQ(Status::OK, status) << "Failure providing "
+                                             "key response for configuration "
+                                          << configuration.name;
+            keySetId = myKeySetId;
+        });
+    EXPECT_OK(res);
+    return keySetId;
+}
+
 /**
  * Test that a session can be opened and closed
  */
 TEST_P(DrmHalVendorPluginTest, OpenCloseSession) {
+    RETURN_IF_SKIPPED;
     auto sessionId = openSession();
     closeSession(sessionId);
 }
@@ -402,6 +491,7 @@
  * is prohibited with the documented error code.
  */
 TEST_P(DrmHalVendorPluginTest, CloseInvalidSession) {
+    RETURN_IF_SKIPPED;
     SessionId invalidSessionId;
     Status status = drmPlugin->closeSession(invalidSessionId);
     EXPECT_EQ(Status::BAD_VALUE, status);
@@ -412,6 +502,7 @@
  * is prohibited with the documented error code.
  */
 TEST_P(DrmHalVendorPluginTest, CloseClosedSession) {
+    RETURN_IF_SKIPPED;
     auto sessionId = openSession();
     closeSession(sessionId);
     Status status = drmPlugin->closeSession(sessionId);
@@ -422,6 +513,7 @@
  * A get key request should fail if no sessionId is provided
  */
 TEST_P(DrmHalVendorPluginTest, GetKeyRequestNoSession) {
+    RETURN_IF_SKIPPED;
     SessionId invalidSessionId;
     hidl_vec<uint8_t> initData;
     hidl_string mimeType = "video/mp4";
@@ -438,6 +530,7 @@
  * Test that an empty sessionID returns BAD_VALUE
  */
 TEST_P(DrmHalVendorPluginTest, ProvideKeyResponseEmptySessionId) {
+    RETURN_IF_SKIPPED;
     SessionId session;
 
     hidl_vec<uint8_t> keyResponse = {0x7b, 0x22, 0x6b, 0x65,
@@ -455,6 +548,7 @@
  * Test that an empty key response returns BAD_VALUE
  */
 TEST_P(DrmHalVendorPluginTest, ProvideKeyResponseEmptyResponse) {
+    RETURN_IF_SKIPPED;
     SessionId session = openSession();
     hidl_vec<uint8_t> emptyResponse;
     auto res = drmPlugin->provideKeyResponse(
@@ -471,6 +565,7 @@
  * Test that a removeKeys on an empty sessionID returns BAD_VALUE
  */
 TEST_P(DrmHalVendorPluginTest, RemoveKeysEmptySessionId) {
+    RETURN_IF_SKIPPED;
     SessionId sessionId;
     Status status = drmPlugin->removeKeys(sessionId);
     EXPECT_TRUE(status == Status::BAD_VALUE);
@@ -481,6 +576,7 @@
  * that has no keys.
  */
 TEST_P(DrmHalVendorPluginTest, RemoveKeysNewSession) {
+    RETURN_IF_SKIPPED;
     SessionId sessionId = openSession();
     Status status = drmPlugin->removeKeys(sessionId);
     EXPECT_TRUE(status == Status::OK);
@@ -488,11 +584,68 @@
 }
 
 /**
+ * Test that keys are successfully restored to a new session
+ * for all content having a policy that allows offline use.
+ */
+TEST_P(DrmHalVendorPluginTest, RestoreKeys) {
+    RETURN_IF_SKIPPED;
+    for (auto config : contentConfigurations) {
+        if (config.policy.allowOffline) {
+            auto sessionId = openSession();
+            hidl_vec<uint8_t> keySetId =
+                    loadKeys(sessionId, config, KeyType::OFFLINE);
+            closeSession(sessionId);
+            sessionId = openSession();
+            EXPECT_NE(0u, keySetId.size());
+            Status status = drmPlugin->restoreKeys(sessionId, keySetId);
+            EXPECT_EQ(Status::OK, status);
+            closeSession(sessionId);
+        }
+    }
+}
+
+/**
+ * Test that restoreKeys fails with a null key set ID.
+ * Error message is expected to be Status::BAD_VALUE.
+ */
+TEST_P(DrmHalVendorPluginTest, RestoreKeysNull) {
+    RETURN_IF_SKIPPED;
+    SessionId sessionId = openSession();
+    hidl_vec<uint8_t> nullKeySetId;
+    Status status = drmPlugin->restoreKeys(sessionId, nullKeySetId);
+    EXPECT_EQ(Status::BAD_VALUE, status);
+    closeSession(sessionId);
+}
+
+/**
+ * Test that restoreKeys fails to restore keys to a closed
+ * session. Error message is expected to be
+ * Status::ERROR_DRM_SESSION_NOT_OPENED.
+ */
+TEST_P(DrmHalVendorPluginTest, RestoreKeysClosedSession) {
+    RETURN_IF_SKIPPED;
+    for (auto config : contentConfigurations) {
+        if (config.policy.allowOffline) {
+            auto sessionId = openSession();
+            hidl_vec<uint8_t> keySetId =
+                    loadKeys(sessionId, config, KeyType::OFFLINE);
+            EXPECT_NE(0u, keySetId.size());
+            closeSession(sessionId);
+            sessionId = openSession();
+            closeSession(sessionId);
+            Status status = drmPlugin->restoreKeys(sessionId, keySetId);
+            EXPECT_EQ(Status::ERROR_DRM_SESSION_NOT_OPENED, status);
+        }
+    }
+}
+
+/**
  * Test that the plugin either doesn't support getting
  * secure stops, or has no secure stops available after
  * clearing them.
  */
 TEST_P(DrmHalVendorPluginTest, GetSecureStops) {
+    RETURN_IF_SKIPPED;
     // There may be secure stops, depending on if there were keys
     // loaded and unloaded previously. Clear them to get to a known
     // state, then make sure there are none.
@@ -520,6 +673,7 @@
  * an empty ssid is provided.
  */
 TEST_P(DrmHalVendorPluginTest, GetSecureStopEmptySSID) {
+    RETURN_IF_SKIPPED;
     SecureStopId ssid;
     auto res = drmPlugin->getSecureStop(
             ssid, [&](Status status, const SecureStop&) {
@@ -533,6 +687,7 @@
  * or is completed successfully
  */
 TEST_P(DrmHalVendorPluginTest, ReleaseAllSecureStops) {
+    RETURN_IF_SKIPPED;
     Status status = drmPlugin->releaseAllSecureStops();
     EXPECT_TRUE(status == Status::OK ||
                 status == Status::ERROR_DRM_CANNOT_HANDLE);
@@ -544,6 +699,7 @@
  * This is an optional API so it can also return CANNOT_HANDLE.
  */
 TEST_P(DrmHalVendorPluginTest, ReleaseSecureStopSequenceError) {
+    RETURN_IF_SKIPPED;
     SecureStopId ssid = {1, 2, 3, 4};
     Status status = drmPlugin->releaseSecureStop(ssid);
     EXPECT_TRUE(status == Status::ERROR_DRM_INVALID_STATE ||
@@ -556,6 +712,7 @@
  * CANNOT_HANDLE.
  */
 TEST_P(DrmHalVendorPluginTest, ReleaseSecureStopEmptySSID) {
+    RETURN_IF_SKIPPED;
     SecureStopId ssid;
     Status status = drmPlugin->releaseSecureStop(ssid);
     EXPECT_TRUE(status == Status::BAD_VALUE ||
@@ -568,6 +725,7 @@
  * the plugin.
  */
 TEST_P(DrmHalVendorPluginTest, GetVendorProperty) {
+    RETURN_IF_SKIPPED;
     auto res = drmPlugin->getPropertyString(
             "vendor", [&](Status status, const hidl_string& value) {
                 EXPECT_EQ(Status::OK, status);
@@ -577,6 +735,7 @@
 }
 
 TEST_P(DrmHalVendorPluginTest, GetVersionProperty) {
+    RETURN_IF_SKIPPED;
     auto res = drmPlugin->getPropertyString(
             "version", [&](Status status, const hidl_string& value) {
                 EXPECT_EQ(Status::OK, status);
@@ -586,6 +745,7 @@
 }
 
 TEST_P(DrmHalVendorPluginTest, GetDescriptionProperty) {
+    RETURN_IF_SKIPPED;
     auto res = drmPlugin->getPropertyString(
             "description", [&](Status status, const hidl_string& value) {
                 EXPECT_EQ(Status::OK, status);
@@ -595,6 +755,7 @@
 }
 
 TEST_P(DrmHalVendorPluginTest, GetAlgorithmsProperty) {
+    RETURN_IF_SKIPPED;
     auto res = drmPlugin->getPropertyString(
             "algorithms", [&](Status status, const hidl_string& value) {
                 if (status == Status::OK) {
@@ -607,6 +768,7 @@
 }
 
 TEST_P(DrmHalVendorPluginTest, GetPropertyUniqueDeviceID) {
+    RETURN_IF_SKIPPED;
     auto res = drmPlugin->getPropertyByteArray(
             "deviceUniqueId",
             [&](Status status, const hidl_vec<uint8_t>& value) {
@@ -624,6 +786,7 @@
  * properties returns the documented error code.
  */
 TEST_P(DrmHalVendorPluginTest, GetInvalidStringProperty) {
+    RETURN_IF_SKIPPED;
     auto res = drmPlugin->getPropertyString(
             "invalid", [&](Status status, const hidl_string&) {
                 EXPECT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status);
@@ -632,6 +795,7 @@
 }
 
 TEST_P(DrmHalVendorPluginTest, GetInvalidByteArrayProperty) {
+    RETURN_IF_SKIPPED;
     auto res = drmPlugin->getPropertyByteArray(
             "invalid", [&](Status status, const hidl_vec<uint8_t>&) {
                 EXPECT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status);
@@ -644,11 +808,13 @@
  * the expected status value.
  */
 TEST_P(DrmHalVendorPluginTest, SetStringPropertyNotSupported) {
+    RETURN_IF_SKIPPED;
     EXPECT_EQ(drmPlugin->setPropertyString("awefijaeflijwef", "value"),
               Status::ERROR_DRM_CANNOT_HANDLE);
 }
 
 TEST_P(DrmHalVendorPluginTest, SetByteArrayPropertyNotSupported) {
+    RETURN_IF_SKIPPED;
     hidl_vec<uint8_t> value;
     EXPECT_EQ(drmPlugin->setPropertyByteArray("awefijaeflijwef", value),
               Status::ERROR_DRM_CANNOT_HANDLE);
@@ -659,6 +825,7 @@
  * the expected status value.
  */
 TEST_P(DrmHalVendorPluginTest, SetCipherInvalidAlgorithm) {
+    RETURN_IF_SKIPPED;
     SessionId session = openSession();
     hidl_string algorithm;
     Status status = drmPlugin->setCipherAlgorithm(session, algorithm);
@@ -671,6 +838,7 @@
  * the expected status value.
  */
 TEST_P(DrmHalVendorPluginTest, SetCipherAlgorithmNoSession) {
+    RETURN_IF_SKIPPED;
     SessionId session;
     hidl_string algorithm = "AES/CBC/NoPadding";
     Status status = drmPlugin->setCipherAlgorithm(session, algorithm);
@@ -684,6 +852,7 @@
  * either accept it or return ERROR_DRM_CANNOT_HANDLE
  */
 TEST_P(DrmHalVendorPluginTest, SetCipherAlgorithm) {
+    RETURN_IF_SKIPPED;
     SessionId session = openSession();
     ;
     hidl_string algorithm = "AES/CBC/NoPadding";
@@ -698,6 +867,7 @@
  * the expected status value.
  */
 TEST_P(DrmHalVendorPluginTest, SetMacInvalidAlgorithm) {
+    RETURN_IF_SKIPPED;
     SessionId session = openSession();
     hidl_string algorithm;
     Status status = drmPlugin->setMacAlgorithm(session, algorithm);
@@ -710,6 +880,7 @@
  * the expected status value.
  */
 TEST_P(DrmHalVendorPluginTest, SetMacNullAlgorithmNoSession) {
+    RETURN_IF_SKIPPED;
     SessionId session;
     hidl_string algorithm = "HmacSHA256";
     Status status = drmPlugin->setMacAlgorithm(session, algorithm);
@@ -723,6 +894,7 @@
  * either accept it or return ERROR_DRM_CANNOT_HANDLE
  */
 TEST_P(DrmHalVendorPluginTest, SetMacAlgorithm) {
+    RETURN_IF_SKIPPED;
     SessionId session = openSession();
     hidl_string algorithm = "HmacSHA256";
     Status status = drmPlugin->setMacAlgorithm(session, algorithm);
@@ -743,6 +915,7 @@
  * inputs, e.g. empty sessionId
  */
 TEST_P(DrmHalVendorPluginTest, GenericEncryptNoSession) {
+    RETURN_IF_SKIPPED;
     SessionId session;
     hidl_vec<uint8_t> keyId, input, iv;
     auto res = drmPlugin->encrypt(
@@ -754,6 +927,7 @@
 }
 
 TEST_P(DrmHalVendorPluginTest, GenericDecryptNoSession) {
+    RETURN_IF_SKIPPED;
     SessionId session;
     hidl_vec<uint8_t> keyId, input, iv;
     auto res = drmPlugin->decrypt(
@@ -765,6 +939,7 @@
 }
 
 TEST_P(DrmHalVendorPluginTest, GenericSignNoSession) {
+    RETURN_IF_SKIPPED;
     SessionId session;
     hidl_vec<uint8_t> keyId, message;
     auto res = drmPlugin->sign(
@@ -776,6 +951,7 @@
 }
 
 TEST_P(DrmHalVendorPluginTest, GenericVerifyNoSession) {
+    RETURN_IF_SKIPPED;
     SessionId session;
     hidl_vec<uint8_t> keyId, message, signature;
     auto res = drmPlugin->verify(
@@ -786,6 +962,7 @@
 }
 
 TEST_P(DrmHalVendorPluginTest, GenericSignRSANoSession) {
+    RETURN_IF_SKIPPED;
     SessionId session;
     hidl_string algorithm;
     hidl_vec<uint8_t> message, wrappedKey;
@@ -806,6 +983,7 @@
  * Verify that requiresSecureDecoderComponent handles empty mimetype.
  */
 TEST_P(DrmHalVendorPluginTest, RequiresSecureDecoderEmptyMimeType) {
+    RETURN_IF_SKIPPED;
     EXPECT_FALSE(cryptoPlugin->requiresSecureDecoderComponent(""));
 }
 
@@ -813,6 +991,7 @@
  * Verify that requiresSecureDecoderComponent handles invalid mimetype.
  */
 TEST_P(DrmHalVendorPluginTest, RequiresSecureDecoderInvalidMimeType) {
+    RETURN_IF_SKIPPED;
     EXPECT_FALSE(cryptoPlugin->requiresSecureDecoderComponent("bad"));
 }
 
@@ -821,7 +1000,7 @@
  * configurations
  */
 TEST_P(DrmHalVendorPluginTest, RequiresSecureDecoderConfig) {
-    const char* kVendorStr = "Vendor module ";
+    RETURN_IF_SKIPPED;
     for (auto config : contentConfigurations) {
         for (auto key : config.keys) {
             if (key.isSecure) {
@@ -893,6 +1072,7 @@
  * gets them.
  */
 TEST_P(DrmHalVendorPluginTest, ListenerEvents) {
+    RETURN_IF_SKIPPED;
     sp<TestDrmPluginListener> listener = new TestDrmPluginListener();
     drmPlugin->setListener(listener);
     auto sessionId = openSession();
@@ -919,6 +1099,7 @@
  * the listener gets them.
  */
 TEST_P(DrmHalVendorPluginTest, ListenerExpirationUpdate) {
+    RETURN_IF_SKIPPED;
     sp<TestDrmPluginListener> listener = new TestDrmPluginListener();
     drmPlugin->setListener(listener);
     auto sessionId = openSession();
@@ -936,6 +1117,7 @@
  * the listener gets them.
  */
 TEST_P(DrmHalVendorPluginTest, ListenerKeysChange) {
+    RETURN_IF_SKIPPED;
     sp<TestDrmPluginListener> listener = new TestDrmPluginListener();
     drmPlugin->setListener(listener);
     auto sessionId = openSession();
@@ -961,6 +1143,7 @@
  * listener set.
  */
 TEST_P(DrmHalVendorPluginTest, NotListening) {
+    RETURN_IF_SKIPPED;
     sp<TestDrmPluginListener> listener = new TestDrmPluginListener();
     drmPlugin->setListener(listener);
     drmPlugin->setListener(nullptr);
@@ -986,6 +1169,7 @@
  * just call the method for coverage.
  */
 TEST_P(DrmHalVendorPluginTest, NotifyResolution) {
+    RETURN_IF_SKIPPED;
     cryptoPlugin->notifyResolution(1920, 1080);
 }
 
@@ -1025,6 +1209,7 @@
  * is used to associate a drm session with a crypto session.
  */
 TEST_P(DrmHalVendorPluginTest, SetMediaDrmSession) {
+    RETURN_IF_SKIPPED;
     auto sessionId = openSession();
     Status status = cryptoPlugin->setMediaDrmSession(sessionId);
     EXPECT_EQ(Status::OK, status);
@@ -1035,6 +1220,7 @@
  * setMediaDrmSession with a closed session id
  */
 TEST_P(DrmHalVendorPluginTest, SetMediaDrmSessionClosedSession) {
+    RETURN_IF_SKIPPED;
     auto sessionId = openSession();
     closeSession(sessionId);
     Status status = cryptoPlugin->setMediaDrmSession(sessionId);
@@ -1045,6 +1231,7 @@
  * setMediaDrmSession with a empty session id: BAD_VALUE
  */
 TEST_P(DrmHalVendorPluginTest, SetMediaDrmSessionEmptySession) {
+    RETURN_IF_SKIPPED;
     SessionId sessionId;
     Status status = cryptoPlugin->setMediaDrmSession(sessionId);
     EXPECT_EQ(Status::BAD_VALUE, status);
@@ -1060,10 +1247,7 @@
     virtual ~DrmHalVendorDecryptTest() {}
 
    protected:
-    void loadKeys(const SessionId& sessionId,
-                  const ContentConfiguration& configuration);
     void fillRandom(const sp<IMemory>& memory);
-    KeyedVector toHidlKeyedVector(const map<string, string>& params);
     hidl_array<uint8_t, 16> toHidlArray(const vector<uint8_t>& vec) {
         EXPECT_EQ(vec.size(), 16u);
         return hidl_array<uint8_t, 16>(&vec[0]);
@@ -1080,63 +1264,6 @@
             const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
 };
 
-KeyedVector DrmHalVendorDecryptTest::toHidlKeyedVector(
-        const map<string, string>& params) {
-    std::vector<KeyValue> stdKeyedVector;
-    for (auto it = params.begin(); it != params.end(); ++it) {
-        KeyValue keyValue;
-        keyValue.key = it->first;
-        keyValue.value = it->second;
-        stdKeyedVector.push_back(keyValue);
-    }
-    return KeyedVector(stdKeyedVector);
-}
-
-/**
- * Helper method to load keys for subsequent decrypt tests.
- * These tests use predetermined key request/response to
- * avoid requiring a round trip to a license server.
- */
-void DrmHalVendorDecryptTest::loadKeys(const SessionId& sessionId,
-        const ContentConfiguration& configuration) {
-    hidl_vec<uint8_t> keyRequest;
-    auto res = drmPlugin->getKeyRequest(
-            sessionId, configuration.initData, configuration.mimeType,
-            KeyType::STREAMING,
-            toHidlKeyedVector(configuration.optionalParameters),
-            [&](Status status, const hidl_vec<uint8_t>& request,
-                KeyRequestType type, const hidl_string&) {
-                EXPECT_EQ(Status::OK, status)
-                        << "Failed to get "
-                           "key request for configuration "
-                        << configuration.name;
-                EXPECT_EQ(type, KeyRequestType::INITIAL);
-                EXPECT_NE(request.size(), 0u) << "Expected key request size"
-                                                 " to have length > 0 bytes";
-                keyRequest = request;
-            });
-    EXPECT_OK(res);
-
-    /**
-     * Get key response from vendor module
-     */
-    hidl_vec<uint8_t> keyResponse =
-            vendorModule->handleKeyRequest(keyRequest, configuration.serverUrl);
-
-    EXPECT_NE(keyResponse.size(), 0u) << "Expected key response size "
-                                         "to have length > 0 bytes";
-
-    res = drmPlugin->provideKeyResponse(
-            sessionId, keyResponse,
-            [&](Status status, const hidl_vec<uint8_t>&) {
-                EXPECT_EQ(Status::OK, status)
-                        << "Failure providing "
-                           "key response for configuration "
-                        << configuration.name;
-            });
-    EXPECT_OK(res);
-}
-
 void DrmHalVendorDecryptTest::fillRandom(const sp<IMemory>& memory) {
     random_device rd;
     mt19937 rand(rd());
@@ -1298,6 +1425,7 @@
  * Test key status with empty session id, should return BAD_VALUE
  */
 TEST_P(DrmHalVendorDecryptTest, QueryKeyStatusInvalidSession) {
+    RETURN_IF_SKIPPED;
     SessionId sessionId;
     auto res = drmPlugin->queryKeyStatus(sessionId,
             [&](Status status, KeyedVector /* info */) {
@@ -1311,6 +1439,7 @@
  * Test key status.  There should be no key status prior to loading keys
  */
 TEST_P(DrmHalVendorDecryptTest, QueryKeyStatusWithNoKeys) {
+    RETURN_IF_SKIPPED;
     auto sessionId = openSession();
     auto keyStatus = queryKeyStatus(sessionId);
     EXPECT_EQ(0u, keyStatus.size());
@@ -1322,6 +1451,7 @@
  * Test key status.  There should be key status after loading keys.
  */
 TEST_P(DrmHalVendorDecryptTest, QueryKeyStatus) {
+    RETURN_IF_SKIPPED;
     for (auto config : contentConfigurations) {
         auto sessionId = openSession();
         loadKeys(sessionId, config);
@@ -1335,6 +1465,7 @@
  * Positive decrypt test. "Decrypt" a single clear segment and verify.
  */
 TEST_P(DrmHalVendorDecryptTest, ClearSegmentTest) {
+    RETURN_IF_SKIPPED;
     for (auto config : contentConfigurations) {
         for (auto key : config.keys) {
             const size_t kSegmentSize = 1024;
@@ -1362,6 +1493,7 @@
  * Verify data matches.
  */
 TEST_P(DrmHalVendorDecryptTest, EncryptedAesCtrSegmentTest) {
+    RETURN_IF_SKIPPED;
     for (auto config : contentConfigurations) {
         for (auto key : config.keys) {
             const size_t kSegmentSize = 1024;
@@ -1388,6 +1520,7 @@
  * Negative decrypt test. Decrypt without loading keys.
  */
 TEST_P(DrmHalVendorDecryptTest, EncryptedAesCtrSegmentTestNoKeys) {
+    RETURN_IF_SKIPPED;
     for (auto config : contentConfigurations) {
         for (auto key : config.keys) {
             vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
@@ -1414,6 +1547,7 @@
  * decryption can't be performed.
  */
 TEST_P(DrmHalVendorDecryptTest, AttemptDecryptWithKeysRemoved) {
+    RETURN_IF_SKIPPED;
     for (auto config : contentConfigurations) {
         for (auto key : config.keys) {
             vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
diff --git a/dumpstate/1.0/default/DumpstateDevice.cpp b/dumpstate/1.0/default/DumpstateDevice.cpp
index 8000d85..213fc62 100644
--- a/dumpstate/1.0/default/DumpstateDevice.cpp
+++ b/dumpstate/1.0/default/DumpstateDevice.cpp
@@ -52,7 +52,7 @@
     dprintf(fd, "Dumpstate HIDL not provided by device; providing bogus data.\n");
 
     // Shows some examples on how to use the libdumpstateutil API.
-    RunCommandToFd(fd, "DATE", {"/system/bin/date"});
+    RunCommandToFd(fd, "DATE", {"/vendor/bin/date"});
     DumpFileToFd(fd, "HOSTS", "/system/etc/hosts");
 
     return Void();
diff --git a/gnss/1.0/default/Android.mk b/gnss/1.0/default/Android.mk
index 5ad5e50..34da64e 100644
--- a/gnss/1.0/default/Android.mk
+++ b/gnss/1.0/default/Android.mk
@@ -45,8 +45,8 @@
     libdl \
     libbase \
     libutils \
-    libhardware_legacy \
     libhardware \
+    libbinder \
 
 LOCAL_SHARED_LIBRARIES += \
     libhidlbase \
diff --git a/gnss/1.0/default/android.hardware.gnss@1.0-service.rc b/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
index f1116f4..96638a3 100644
--- a/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
+++ b/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
@@ -1,7 +1,4 @@
 service gnss_service /vendor/bin/hw/android.hardware.gnss@1.0-service
     class main
     user system
-#
-# TODO:(b/35757613) - STOPSHIP - HAL cannot have direct inet access
-#
-    group system inet
+    group system gps
diff --git a/gnss/1.0/default/service.cpp b/gnss/1.0/default/service.cpp
index 5a8acc1..0704e7f 100644
--- a/gnss/1.0/default/service.cpp
+++ b/gnss/1.0/default/service.cpp
@@ -4,9 +4,14 @@
 
 #include <hidl/LegacySupport.h>
 
+#include <binder/ProcessState.h>
+
 using android::hardware::gnss::V1_0::IGnss;
 using android::hardware::defaultPassthroughServiceImplementation;
 
 int main() {
+    // The GNSS HAL may communicate to other vendor components via
+    // /dev/vndbinder
+    android::ProcessState::initWithDriver("/dev/vndbinder");
     return defaultPassthroughServiceImplementation<IGnss>();
 }
diff --git a/keymaster/3.0/default/Android.mk b/keymaster/3.0/default/Android.mk
index c537346..9df5bf8 100644
--- a/keymaster/3.0/default/Android.mk
+++ b/keymaster/3.0/default/Android.mk
@@ -34,7 +34,6 @@
     libdl \
     libbase \
     libutils \
-    libhardware_legacy \
     libhardware \
     libhidlbase \
     libhidltransport \
diff --git a/keymaster/3.0/default/KeymasterDevice.cpp b/keymaster/3.0/default/KeymasterDevice.cpp
index 6b4524b..58102bb 100644
--- a/keymaster/3.0/default/KeymasterDevice.cpp
+++ b/keymaster/3.0/default/KeymasterDevice.cpp
@@ -519,6 +519,7 @@
 
     hidl_vec<hidl_vec<uint8_t>> resultCertChain;
 
+    bool foundAttestationApplicationId = false;
     for (size_t i = 0; i < attestParams.size(); ++i) {
         switch (attestParams[i].tag) {
         case Tag::ATTESTATION_ID_BRAND:
@@ -532,11 +533,22 @@
             // never perform any device id attestation.
             _hidl_cb(ErrorCode::CANNOT_ATTEST_IDS, resultCertChain);
             return Void();
+
+        case Tag::ATTESTATION_APPLICATION_ID:
+            foundAttestationApplicationId = true;
+            break;
+
         default:
             break;
         }
     }
 
+    // KM3 devices reject missing attest application IDs. KM2 devices do not.
+    if (!foundAttestationApplicationId) {
+        _hidl_cb(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING,
+                 resultCertChain);
+    }
+
     keymaster_cert_chain_t cert_chain{nullptr, 0};
 
     auto kmKeyToAttest = hidlVec2KmKeyBlob(keyToAttest);
diff --git a/keymaster/3.0/vts/functional/attestation_record.cpp b/keymaster/3.0/vts/functional/attestation_record.cpp
index 6cdd44c..5d96fff 100644
--- a/keymaster/3.0/vts/functional/attestation_record.cpp
+++ b/keymaster/3.0/vts/functional/attestation_record.cpp
@@ -244,6 +244,8 @@
     copyAuthTag(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list);
     copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list);
     copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list);
+    copyAuthTag(record->attestation_application_id,
+                TAG_ATTESTATION_APPLICATION_ID, auth_list);
 
     return ErrorCode::OK;
 }
diff --git a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
index edb1cd1..3448398 100644
--- a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -892,19 +892,10 @@
     static hidl_string author_;
 };
 
-uint32_t expected_keymaster_version() {
-    if (!KeymasterHidlTest::IsSecure()) return 2;  // SW is KM2
-
-    uint32_t keymaster_version = 0;
-    if (KeymasterHidlTest::SupportsSymmetric()) keymaster_version = 1;
-    if (KeymasterHidlTest::SupportsAttestation()) keymaster_version = 2;
-    return keymaster_version;
-}
-
-bool verify_attestation_record(const string& challenge, AuthorizationSet expected_sw_enforced,
+bool verify_attestation_record(const string& challenge, const string& app_id,
+                               AuthorizationSet expected_sw_enforced,
                                AuthorizationSet expected_tee_enforced,
                                const hidl_vec<uint8_t>& attestation_cert) {
-
     X509_Ptr cert(parse_cert_blob(attestation_cert));
     EXPECT_TRUE(!!cert.get());
     if (!cert.get()) return false;
@@ -921,6 +912,7 @@
     SecurityLevel att_keymaster_security_level;
     HidlBuf att_challenge;
     HidlBuf att_unique_id;
+    HidlBuf att_app_id;
     EXPECT_EQ(ErrorCode::OK,
               parse_attestation_record(attest_rec->data,                 //
                                        attest_rec->length,               //
@@ -933,8 +925,28 @@
                                        &att_tee_enforced,                //
                                        &att_unique_id));
 
-    EXPECT_EQ(1U, att_attestation_version);
-    EXPECT_EQ(expected_keymaster_version(), att_keymaster_version);
+    if (att_keymaster_version == 3) {
+        EXPECT_EQ(2U, att_attestation_version);
+    } else {
+        EXPECT_EQ(1U, att_attestation_version);
+    }
+
+    expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID,
+                                   HidlBuf(app_id));
+
+    if (!KeymasterHidlTest::IsSecure()) {
+        // SW is KM2
+        EXPECT_EQ(att_keymaster_version, 2U);
+    }
+
+    if (KeymasterHidlTest::SupportsSymmetric()) {
+        EXPECT_GE(att_keymaster_version, 1U);
+    }
+
+    if (KeymasterHidlTest::SupportsAttestation()) {
+        EXPECT_GE(att_keymaster_version, 2U);
+    }
+
     EXPECT_EQ(KeymasterHidlTest::IsSecure() ? SecurityLevel::TRUSTED_ENVIRONMENT
                                             : SecurityLevel::SOFTWARE,
               att_keymaster_security_level);
@@ -3827,15 +3839,41 @@
                                              .Authorization(TAG_INCLUDE_UNIQUE_ID)));
 
     hidl_vec<hidl_vec<uint8_t>> cert_chain;
-    EXPECT_EQ(ErrorCode::OK, AttestKey(AuthorizationSetBuilder().Authorization(
-                                           TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge")),
-                                       &cert_chain));
+    EXPECT_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",                            //
-                                          key_characteristics_.softwareEnforced,  //
-                                          key_characteristics_.teeEnforced,       //
-                                          cert_chain[0]));
+    EXPECT_TRUE(
+        verify_attestation_record("challenge", "foo",                     //
+                                  key_characteristics_.softwareEnforced,  //
+                                  key_characteristics_.teeEnforced,       //
+                                  cert_chain[0]));
+}
+
+/*
+ * AttestationTest.RsaAttestationRequiresAppId
+ *
+ * Verifies that attesting to RSA requires app ID.
+ */
+TEST_F(AttestationTest, RsaAttestationRequiresAppId) {
+    ASSERT_EQ(ErrorCode::OK,
+              GenerateKey(AuthorizationSetBuilder()
+                              .Authorization(TAG_NO_AUTH_REQUIRED)
+                              .RsaSigningKey(1024, 3)
+                              .Digest(Digest::NONE)
+                              .Padding(PaddingMode::NONE)
+                              .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+    hidl_vec<hidl_vec<uint8_t>> cert_chain;
+    EXPECT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING,
+              AttestKey(AuthorizationSetBuilder().Authorization(
+                            TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge")),
+                        &cert_chain));
 }
 
 /*
@@ -3851,16 +3889,41 @@
                                              .Authorization(TAG_INCLUDE_UNIQUE_ID)));
 
     hidl_vec<hidl_vec<uint8_t>> cert_chain;
-    EXPECT_EQ(ErrorCode::OK, AttestKey(AuthorizationSetBuilder().Authorization(
-                                           TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge")),
-                                       &cert_chain));
+    EXPECT_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",                            //
-                                          key_characteristics_.softwareEnforced,  //
-                                          key_characteristics_.teeEnforced,       //
-                                          cert_chain[0]));
+    EXPECT_TRUE(
+        verify_attestation_record("challenge", "foo",                     //
+                                  key_characteristics_.softwareEnforced,  //
+                                  key_characteristics_.teeEnforced,       //
+                                  cert_chain[0]));
+}
+
+/*
+ * AttestationTest.EcAttestationRequiresAttestationAppId
+ *
+ * Verifies that attesting to EC keys requires app ID
+ */
+TEST_F(AttestationTest, EcAttestationRequiresAttestationAppId) {
+    ASSERT_EQ(ErrorCode::OK,
+              GenerateKey(AuthorizationSetBuilder()
+                              .Authorization(TAG_NO_AUTH_REQUIRED)
+                              .EcdsaSigningKey(EcCurve::P_256)
+                              .Digest(Digest::SHA_2_256)
+                              .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+    hidl_vec<hidl_vec<uint8_t>> cert_chain;
+    EXPECT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING,
+              AttestKey(AuthorizationSetBuilder().Authorization(
+                            TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge")),
+                        &cert_chain));
 }
 
 /*
@@ -3932,15 +3995,18 @@
     AuthorizationSet begin_out_params;
 
     if (rollback_protected) {
-        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
-                Begin(KeyPurpose::SIGN, key_blob_,
-                        AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
-                        &begin_out_params, &op_handle_));
+        EXPECT_EQ(
+            ErrorCode::INVALID_KEY_BLOB,
+            Begin(KeyPurpose::SIGN, key_blob_, AuthorizationSetBuilder()
+                                                   .Digest(Digest::NONE)
+                                                   .Padding(PaddingMode::NONE),
+                  &begin_out_params, &op_handle_));
     } else {
-        EXPECT_EQ(ErrorCode::OK,
-                Begin(KeyPurpose::SIGN, key_blob_,
-                        AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
-                        &begin_out_params, &op_handle_));
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, key_blob_,
+                                       AuthorizationSetBuilder()
+                                           .Digest(Digest::NONE)
+                                           .Padding(PaddingMode::NONE),
+                                       &begin_out_params, &op_handle_));
     }
     AbortIfNeeded();
     key_blob_ = HidlBuf();
@@ -4006,15 +4072,18 @@
     AuthorizationSet begin_out_params;
 
     if (rollback_protected) {
-        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
-                Begin(KeyPurpose::SIGN, key_blob_,
-                        AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
-                        &begin_out_params, &op_handle_));
+        EXPECT_EQ(
+            ErrorCode::INVALID_KEY_BLOB,
+            Begin(KeyPurpose::SIGN, key_blob_, AuthorizationSetBuilder()
+                                                   .Digest(Digest::NONE)
+                                                   .Padding(PaddingMode::NONE),
+                  &begin_out_params, &op_handle_));
     } else {
-        EXPECT_EQ(ErrorCode::OK,
-                Begin(KeyPurpose::SIGN, key_blob_,
-                        AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
-                        &begin_out_params, &op_handle_));
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, key_blob_,
+                                       AuthorizationSetBuilder()
+                                           .Digest(Digest::NONE)
+                                           .Padding(PaddingMode::NONE),
+                                       &begin_out_params, &op_handle_));
     }
     AbortIfNeeded();
     key_blob_ = HidlBuf();
diff --git a/light/2.0/default/Android.mk b/light/2.0/default/Android.mk
index 3439c9b..1f44e66 100644
--- a/light/2.0/default/Android.mk
+++ b/light/2.0/default/Android.mk
@@ -34,7 +34,6 @@
     libdl \
     libbase \
     libutils \
-    libhardware_legacy \
     libhardware \
 
 LOCAL_SHARED_LIBRARIES += \
diff --git a/nfc/1.0/default/Android.mk b/nfc/1.0/default/Android.mk
index 2e1f17f..4afad74 100644
--- a/nfc/1.0/default/Android.mk
+++ b/nfc/1.0/default/Android.mk
@@ -14,7 +14,6 @@
 	libdl \
 	libbase \
 	libutils \
-	libhardware_legacy \
 	libhardware \
 
 LOCAL_SHARED_LIBRARIES += \
diff --git a/renderscript/1.0/vts/functional/VtsScriptTests.cpp b/renderscript/1.0/vts/functional/VtsScriptTests.cpp
index fed7c6e..8268dcc 100644
--- a/renderscript/1.0/vts/functional/VtsScriptTests.cpp
+++ b/renderscript/1.0/vts/functional/VtsScriptTests.cpp
@@ -323,27 +323,30 @@
 
 /*
  * This test groups together two RenderScript intrinsic kernels to run one after
- * the other asynchronously with respect to the client. The test configures YuvToRGB(A) and Blur,
- * and links them together such that Blur will execute after YuvToRGB(A) and use its result. The
- * test checks the data returned to make sure it was changed after passing through the entire
- * ScriptGroup.
+ * the other asynchronously with respect to the client. The test configures
+ * Blend and Blur, and links them together such that Blur will execute after
+ * Blend and use its result. The test checks the data returned to make sure it
+ * was changed after passing through the entire ScriptGroup.
  *
  * Calls: elementCreate, typeCreate, allocationCreateTyped, allocation2DWrite,
  * scriptIntrinsicCreate, scriptKernelIDCreate, scriptFieldIDCreate,
- * scriptGroupCreate, scriptSetVarObj, scriptGroupSetOutput, scriptGroupExecute,
- * contextFinish, allocation2DRead
+ * scriptGroupCreate, scriptGroupSetInput, scriptGroupSetOutput,
+ * scriptGroupExecute, contextFinish, allocation2DRead
  */
 TEST_F(RenderscriptHidlTest, ScriptGroupTest) {
-    std::vector<uint8_t> dataIn(256*256*1, 128), dataOut(256*256*4, 0), zeros(256*256*4, 0);
+    std::vector<uint8_t> dataIn(256 * 256 * 4, 128), dataOut(256 * 256 * 4, 0),
+        zeros(256 * 256 * 4, 0);
     hidl_vec<uint8_t> _dataIn, _dataOut;
     _dataIn.setToExternal(dataIn.data(), dataIn.size());
     _dataOut.setToExternal(dataOut.data(), dataOut.size());
 
     // 256 x 256 YUV pixels
-    Element element1 = context->elementCreate(DataType::UNSIGNED_8, DataKind::PIXEL_YUV, true, 1);
+    Element element1 = context->elementCreate(DataType::UNSIGNED_8,
+                                              DataKind::PIXEL_RGBA, true, 4);
     ASSERT_NE(Element(0), element1);
 
-    Type type1 = context->typeCreate(element1, 256, 256, 0, false, false, YuvFormat::YUV_420_888);
+    Type type1 = context->typeCreate(element1, 256, 256, 0, false, false,
+                                     YuvFormat::YUV_NONE);
     ASSERT_NE(Type(0), type1);
 
     Allocation allocation1 = context->allocationCreateTyped(type1, AllocationMipmapControl::NONE,
@@ -370,11 +373,12 @@
                                _dataOut, 0);
 
     // create scripts
-    Script yuv2rgb = context->scriptIntrinsicCreate(ScriptIntrinsicID::ID_YUV_TO_RGB, element1);
-    ASSERT_NE(Script(0), yuv2rgb);
+    Script blend =
+        context->scriptIntrinsicCreate(ScriptIntrinsicID::ID_BLEND, element1);
+    ASSERT_NE(Script(0), blend);
 
-    ScriptKernelID yuv2rgbKID = context->scriptKernelIDCreate(yuv2rgb, 0, 2);
-    ASSERT_NE(ScriptKernelID(0), yuv2rgbKID);
+    ScriptKernelID blendKID = context->scriptKernelIDCreate(blend, 1, 3);
+    ASSERT_NE(ScriptKernelID(0), blendKID);
 
     Script blur = context->scriptIntrinsicCreate(ScriptIntrinsicID::ID_BLUR, element2);
     ASSERT_NE(Script(0), blur);
@@ -386,15 +390,15 @@
     ASSERT_NE(ScriptFieldID(0), blurFID);
 
     // ScriptGroup
-    hidl_vec<ScriptKernelID> kernels = {yuv2rgbKID, blurKID};
-    hidl_vec<ScriptKernelID> srcK = {yuv2rgbKID};
+    hidl_vec<ScriptKernelID> kernels = {blendKID, blurKID};
+    hidl_vec<ScriptKernelID> srcK = {blendKID};
     hidl_vec<ScriptKernelID> dstK = {ScriptKernelID(0)};
     hidl_vec<ScriptFieldID> dstF = {blurFID};
     hidl_vec<Type> types = {type2};
     ScriptGroup scriptGroup = context->scriptGroupCreate(kernels, srcK, dstK, dstF, types);
     ASSERT_NE(ScriptGroup(0), scriptGroup);
 
-    context->scriptSetVarObj(yuv2rgb, 0, (ObjectBase)allocation1);
+    context->scriptGroupSetInput(scriptGroup, blendKID, allocation1);
     context->scriptGroupSetOutput(scriptGroup, blurKID, allocation2);
     context->scriptGroupExecute(scriptGroup);
     context->contextFinish();
diff --git a/sensors/1.0/default/Android.mk b/sensors/1.0/default/Android.mk
index bc1cfbd..d114542 100644
--- a/sensors/1.0/default/Android.mk
+++ b/sensors/1.0/default/Android.mk
@@ -14,8 +14,6 @@
         libdl \
         libbase \
         libutils \
-        libhardware_legacy \
-        libhardware \
 
 LOCAL_SHARED_LIBRARIES += \
         libhidlbase \
diff --git a/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp b/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
index b0aef4b..996519b 100644
--- a/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
+++ b/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
@@ -294,8 +294,8 @@
     return ret;
 }
 
-SoundTriggerHalImpl::SoundTriggerHalImpl(const char *moduleName)
-    : mModuleName(moduleName), mHwDevice(NULL), mNextModelId(1)
+SoundTriggerHalImpl::SoundTriggerHalImpl()
+    : mModuleName("primary"), mHwDevice(NULL), mNextModelId(1)
 {
 }
 
@@ -304,9 +304,6 @@
     const hw_module_t *mod;
     int rc;
 
-    if (mModuleName == NULL || strlen(mModuleName) == 0) {
-        mModuleName = "primary";
-    }
     rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, &mod);
     if (rc != 0) {
         ALOGE("couldn't load sound trigger module %s.%s (%s)",
@@ -570,20 +567,9 @@
     delete[] levels;
 }
 
-ISoundTriggerHw *HIDL_FETCH_ISoundTriggerHw(const char *name)
+ISoundTriggerHw *HIDL_FETCH_ISoundTriggerHw(const char* /* name */)
 {
-    if (name != NULL) {
-        if (strncmp(SOUND_TRIGGER_HARDWARE_MODULE_ID, name,
-                strlen(SOUND_TRIGGER_HARDWARE_MODULE_ID)) != 0) {
-            return NULL;
-        }
-        name = strchr(name, '.');
-        if (name == NULL) {
-            return NULL;
-        }
-        name++;
-    }
-    return new SoundTriggerHalImpl(name);
+    return new SoundTriggerHalImpl();
 }
 } // namespace implementation
 }  // namespace V2_0
diff --git a/soundtrigger/2.0/default/SoundTriggerHalImpl.h b/soundtrigger/2.0/default/SoundTriggerHalImpl.h
index 8aa9285..4769590 100644
--- a/soundtrigger/2.0/default/SoundTriggerHalImpl.h
+++ b/soundtrigger/2.0/default/SoundTriggerHalImpl.h
@@ -38,7 +38,7 @@
 
 class SoundTriggerHalImpl : public ISoundTriggerHw {
 public:
-        explicit SoundTriggerHalImpl(const char *moduleName = NULL);
+        SoundTriggerHalImpl();
 
         // Methods from ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw follow.
         Return<void> getProperties(getProperties_cb _hidl_cb)  override;
diff --git a/thermal/1.0/default/Android.mk b/thermal/1.0/default/Android.mk
index 2d25dc3..113020a 100644
--- a/thermal/1.0/default/Android.mk
+++ b/thermal/1.0/default/Android.mk
@@ -29,7 +29,6 @@
         libdl \
         libbase \
         libutils \
-        libhardware_legacy \
         libhardware \
 
 LOCAL_SHARED_LIBRARIES += \