Merge "move VTS HIDL HAL tests to the corresponding interface directories"
diff --git a/audio/2.0/default/Android.mk b/audio/2.0/default/Android.mk
index 5108448..2b1aa4f 100644
--- a/audio/2.0/default/Android.mk
+++ b/audio/2.0/default/Android.mk
@@ -66,6 +66,7 @@
     android.hardware.audio.common@2.0 \
     android.hardware.audio.effect@2.0 \
     android.hardware.soundtrigger@2.0 \
+    android.hardware.broadcastradio@1.0
 
 ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
 LOCAL_MULTILIB := 32
diff --git a/audio/2.0/default/Device.cpp b/audio/2.0/default/Device.cpp
index 05824c7..339f371 100644
--- a/audio/2.0/default/Device.cpp
+++ b/audio/2.0/default/Device.cpp
@@ -520,7 +520,7 @@
     return setParametersImpl(parameters);
 }
 
-Return<void> Device::debugDump(const native_handle_t* fd)  {
+Return<void> Device::debugDump(const hidl_handle& fd)  {
     if (fd->numFds == 1) {
         analyzeStatus("dump", mDevice->dump(mDevice, fd->data[0]));
     }
diff --git a/audio/2.0/default/Device.h b/audio/2.0/default/Device.h
index d7b3128..3fd67e3 100644
--- a/audio/2.0/default/Device.h
+++ b/audio/2.0/default/Device.h
@@ -102,7 +102,7 @@
     Return<void> getParameters(
             const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb)  override;
     Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters)  override;
-    Return<void> debugDump(const native_handle_t* fd)  override;
+    Return<void> debugDump(const hidl_handle& fd)  override;
 
     // Utility methods for extending interfaces.
     Result analyzeStatus(const char* funcName, int status);
diff --git a/audio/2.0/default/PrimaryDevice.cpp b/audio/2.0/default/PrimaryDevice.cpp
index 9f5180c..a8aa5ec 100644
--- a/audio/2.0/default/PrimaryDevice.cpp
+++ b/audio/2.0/default/PrimaryDevice.cpp
@@ -119,7 +119,7 @@
     return mDevice->setParameters(parameters);
 }
 
-Return<void> PrimaryDevice::debugDump(const native_handle_t* fd)  {
+Return<void> PrimaryDevice::debugDump(const hidl_handle& fd)  {
     return mDevice->debugDump(fd);
 }
 
diff --git a/audio/2.0/default/PrimaryDevice.h b/audio/2.0/default/PrimaryDevice.h
index 4c5b590..968c208 100644
--- a/audio/2.0/default/PrimaryDevice.h
+++ b/audio/2.0/default/PrimaryDevice.h
@@ -88,7 +88,7 @@
     Return<void> getParameters(
             const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb)  override;
     Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters)  override;
-    Return<void> debugDump(const native_handle_t* fd)  override;
+    Return<void> debugDump(const hidl_handle& fd)  override;
 
     // Methods from ::android::hardware::audio::V2_0::IPrimaryDevice follow.
     Return<Result> setVoiceVolume(float volume)  override;
diff --git a/audio/2.0/default/Stream.cpp b/audio/2.0/default/Stream.cpp
index 7616bec..6d68f55 100644
--- a/audio/2.0/default/Stream.cpp
+++ b/audio/2.0/default/Stream.cpp
@@ -222,7 +222,7 @@
     return setParametersImpl(parameters);
 }
 
-Return<void> Stream::debugDump(const native_handle_t* fd)  {
+Return<void> Stream::debugDump(const hidl_handle& fd)  {
     if (fd->numFds == 1) {
         analyzeStatus("dump", mStream->dump(mStream, fd->data[0]));
     }
diff --git a/audio/2.0/default/Stream.h b/audio/2.0/default/Stream.h
index f28fbff..3893af4 100644
--- a/audio/2.0/default/Stream.h
+++ b/audio/2.0/default/Stream.h
@@ -70,7 +70,7 @@
     Return<void> getParameters(
             const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb)  override;
     Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters)  override;
-    Return<void> debugDump(const native_handle_t* fd)  override;
+    Return<void> debugDump(const hidl_handle& fd)  override;
 
     // Utility methods for extending interfaces.
     Result analyzeStatus(const char* funcName, int status);
diff --git a/audio/2.0/default/StreamIn.cpp b/audio/2.0/default/StreamIn.cpp
index b590d1a..791e519 100644
--- a/audio/2.0/default/StreamIn.cpp
+++ b/audio/2.0/default/StreamIn.cpp
@@ -126,7 +126,7 @@
     return mStreamCommon->setParameters(parameters);
 }
 
-Return<void> StreamIn::debugDump(const native_handle_t* fd)  {
+Return<void> StreamIn::debugDump(const hidl_handle& fd)  {
     return mStreamCommon->debugDump(fd);
 }
 
diff --git a/audio/2.0/default/StreamIn.h b/audio/2.0/default/StreamIn.h
index 83f620c..c2a7ea2 100644
--- a/audio/2.0/default/StreamIn.h
+++ b/audio/2.0/default/StreamIn.h
@@ -72,7 +72,7 @@
     Return<void> getParameters(
             const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb)  override;
     Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters)  override;
-    Return<void> debugDump(const native_handle_t* fd)  override;
+    Return<void> debugDump(const hidl_handle& fd)  override;
 
     // Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
     Return<void> getAudioSource(getAudioSource_cb _hidl_cb)  override;
diff --git a/audio/2.0/default/StreamOut.cpp b/audio/2.0/default/StreamOut.cpp
index 34bae29..2106256 100644
--- a/audio/2.0/default/StreamOut.cpp
+++ b/audio/2.0/default/StreamOut.cpp
@@ -128,7 +128,7 @@
     return mStreamCommon->setParameters(parameters);
 }
 
-Return<void> StreamOut::debugDump(const native_handle_t* fd)  {
+Return<void> StreamOut::debugDump(const hidl_handle& fd)  {
     return mStreamCommon->debugDump(fd);
 }
 
diff --git a/audio/2.0/default/StreamOut.h b/audio/2.0/default/StreamOut.h
index 51b7df8..ca33b2d 100644
--- a/audio/2.0/default/StreamOut.h
+++ b/audio/2.0/default/StreamOut.h
@@ -74,7 +74,7 @@
     Return<void> getParameters(
             const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb)  override;
     Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters)  override;
-    Return<void> debugDump(const native_handle_t* fd)  override;
+    Return<void> debugDump(const hidl_handle& fd)  override;
 
     // Methods from ::android::hardware::audio::V2_0::IStreamOut follow.
     Return<uint32_t> getLatency()  override;
diff --git a/audio/2.0/default/service.cpp b/audio/2.0/default/service.cpp
index 147f7b9..28ef660 100644
--- a/audio/2.0/default/service.cpp
+++ b/audio/2.0/default/service.cpp
@@ -20,6 +20,7 @@
 #include <android/hardware/audio/2.0/IDevicesFactory.h>
 #include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
+#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
 
 using android::hardware::IPCThreadState;
 using android::hardware::ProcessState;
@@ -27,10 +28,12 @@
 using android::hardware::audio::V2_0::IDevicesFactory;
 using android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
 using android::hardware::registerPassthroughServiceImplementation;
+using android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory;
 
 int main(int /* argc */, char* /* argv */ []) {
     registerPassthroughServiceImplementation<IDevicesFactory>("audio_devices_factory");
     registerPassthroughServiceImplementation<IEffectsFactory>("audio_effects_factory");
     registerPassthroughServiceImplementation<ISoundTriggerHw>("sound_trigger.primary");
+    registerPassthroughServiceImplementation<IBroadcastRadioFactory>("broadcastradio");
     return android::hardware::launchRpcServer(16);
 }
diff --git a/audio/effect/2.0/default/EffectsFactory.cpp b/audio/effect/2.0/default/EffectsFactory.cpp
index 30fcb26..2b5d70b 100644
--- a/audio/effect/2.0/default/EffectsFactory.cpp
+++ b/audio/effect/2.0/default/EffectsFactory.cpp
@@ -182,7 +182,7 @@
     return Void();
 }
 
-Return<void> EffectsFactory::debugDump(const native_handle_t* fd)  {
+Return<void> EffectsFactory::debugDump(const hidl_handle& fd)  {
     if (fd->numFds == 1) {
         EffectDumpEffects(fd->data[0]);
     }
diff --git a/audio/effect/2.0/default/EffectsFactory.h b/audio/effect/2.0/default/EffectsFactory.h
index 229356f..d934c93 100644
--- a/audio/effect/2.0/default/EffectsFactory.h
+++ b/audio/effect/2.0/default/EffectsFactory.h
@@ -47,7 +47,7 @@
     Return<void> getDescriptor(const Uuid& uid, getDescriptor_cb _hidl_cb)  override;
     Return<void> createEffect(
             const Uuid& uid, int32_t session, int32_t ioHandle, createEffect_cb _hidl_cb)  override;
-    Return<void> debugDump(const native_handle_t* fd)  override;
+    Return<void> debugDump(const hidl_handle& fd)  override;
 
   private:
     static sp<IEffect> dispatchEffectInstanceCreation(
diff --git a/broadcastradio/1.0/ITunerCallback.hal b/broadcastradio/1.0/ITunerCallback.hal
index f805472..a7e1260 100644
--- a/broadcastradio/1.0/ITunerCallback.hal
+++ b/broadcastradio/1.0/ITunerCallback.hal
@@ -72,7 +72,9 @@
     /*
      * Method called by the HAL when metadata for current station
      * are updated.
-     * @param metadatas A list of all updated metada.
+     * @param channel The channel the metadata is associated with.
+     * @param subChannel The sub channel the metadata is associated with.
+     * @param metadata A list of all updated metada.
      */
-    oneway newMetadata(vec<MetaData>  metadatas);
+    oneway newMetadata(uint32_t channel, uint32_t subChannel, vec<MetaData>  metadata);
 };
\ No newline at end of file
diff --git a/broadcastradio/1.0/default/Android.mk b/broadcastradio/1.0/default/Android.mk
new file mode 100644
index 0000000..734a0e1
--- /dev/null
+++ b/broadcastradio/1.0/default/Android.mk
@@ -0,0 +1,28 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.broadcastradio@1.0-impl
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+    BroadcastRadio.cpp \
+    BroadcastRadioFactory.cpp \
+    Tuner.cpp \
+    Utils.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libhidlbase \
+    libhidltransport \
+    libhwbinder \
+    libutils \
+    liblog \
+    libhardware \
+    android.hardware.broadcastradio@1.0 \
+    libradio_metadata
+
+ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
+LOCAL_MULTILIB := 32
+else
+LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/broadcastradio/1.0/default/BroadcastRadio.cpp b/broadcastradio/1.0/default/BroadcastRadio.cpp
new file mode 100644
index 0000000..b97b609
--- /dev/null
+++ b/broadcastradio/1.0/default/BroadcastRadio.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BroadcastRadio"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <hardware/radio.h>
+
+#include "BroadcastRadio.h"
+#include "Tuner.h"
+#include "Utils.h"
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+namespace implementation {
+
+BroadcastRadio::BroadcastRadio(Class classId)
+    : mStatus(Result::NOT_INITIALIZED), mClassId(classId), mHwDevice(NULL)
+{
+}
+
+BroadcastRadio::~BroadcastRadio()
+{
+    if (mHwDevice != NULL) {
+        radio_hw_device_close(mHwDevice);
+    }
+}
+
+void BroadcastRadio::onFirstRef()
+{
+    const hw_module_t *mod;
+    int rc;
+    ALOGI("%s mClassId %d", __FUNCTION__, mClassId);
+
+    mHwDevice = NULL;
+    const char *classString = Utils::getClassString(mClassId);
+    if (classString == NULL) {
+        ALOGE("invalid class ID %d", mClassId);
+        mStatus = Result::INVALID_ARGUMENTS;
+        return;
+    }
+
+    ALOGI("%s RADIO_HARDWARE_MODULE_ID %s %s",
+          __FUNCTION__, RADIO_HARDWARE_MODULE_ID, classString);
+
+    rc = hw_get_module_by_class(RADIO_HARDWARE_MODULE_ID, classString, &mod);
+    if (rc != 0) {
+        ALOGE("couldn't load radio module %s.%s (%s)",
+              RADIO_HARDWARE_MODULE_ID, classString, strerror(-rc));
+        return;
+    }
+    rc = radio_hw_device_open(mod, &mHwDevice);
+    if (rc != 0) {
+        ALOGE("couldn't open radio hw device in %s.%s (%s)",
+              RADIO_HARDWARE_MODULE_ID, "primary", strerror(-rc));
+        mHwDevice = NULL;
+        return;
+    }
+    if (mHwDevice->common.version != RADIO_DEVICE_API_VERSION_CURRENT) {
+        ALOGE("wrong radio hw device version %04x", mHwDevice->common.version);
+        radio_hw_device_close(mHwDevice);
+        mHwDevice = NULL;
+    } else {
+        mStatus = Result::OK;
+    }
+}
+
+int BroadcastRadio::closeHalTuner(const struct radio_tuner *halTuner)
+{
+    ALOGV("%s", __FUNCTION__);
+    if (mHwDevice == NULL) {
+        return -ENODEV;
+    }
+    if (halTuner == 0) {
+        return -EINVAL;
+    }
+    return mHwDevice->close_tuner(mHwDevice, halTuner);
+}
+
+
+// Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadio follow.
+Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb)
+{
+    int rc;
+    radio_hal_properties_t halProperties;
+    Properties properties;
+
+    if (mHwDevice == NULL) {
+        rc = -ENODEV;
+        goto exit;
+    }
+    rc = mHwDevice->get_properties(mHwDevice, &halProperties);
+    if (rc == 0) {
+        Utils::convertPropertiesFromHal(&properties, &halProperties);
+    }
+
+exit:
+    _hidl_cb(Utils::convertHalResult(rc), properties);
+    return Void();
+}
+
+Return<void> BroadcastRadio::openTuner(const BandConfig& config, bool audio,
+                                       const sp<ITunerCallback>& callback, openTuner_cb _hidl_cb)
+{
+    sp<Tuner> tunerImpl = new Tuner(callback, this);
+
+    radio_hal_band_config_t halConfig;
+    const struct radio_tuner *halTuner;
+    Utils::convertBandConfigToHal(&halConfig, &config);
+    int rc = mHwDevice->open_tuner(mHwDevice, &halConfig, audio,
+                                   Tuner::callback, tunerImpl.get(),
+                                   &halTuner);
+    if (rc == 0) {
+        tunerImpl->setHalTuner(halTuner);
+    }
+
+    _hidl_cb(Utils::convertHalResult(rc), tunerImpl);
+    return Void();
+}
+
+
+} // namespace implementation
+}  // namespace V1_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/1.0/default/BroadcastRadio.h b/broadcastradio/1.0/default/BroadcastRadio.h
new file mode 100644
index 0000000..dbd6e07
--- /dev/null
+++ b/broadcastradio/1.0/default/BroadcastRadio.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef HIDL_GENERATED_android_hardware_broadcastradio_V1_0_BroadcastRadio_H_
+#define HIDL_GENERATED_android_hardware_broadcastradio_V1_0_BroadcastRadio_H_
+
+#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h>
+#include <hidl/Status.h>
+#include <hardware/radio.h>
+
+#include <hidl/MQDescriptor.h>
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+namespace implementation {
+
+struct BroadcastRadio : public IBroadcastRadio {
+
+            BroadcastRadio(Class classId);
+
+            // Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadio follow.
+            Return<void> getProperties(getProperties_cb _hidl_cb)  override;
+            Return<void> openTuner(const BandConfig& config, bool audio,
+                                   const sp<ITunerCallback>& callback,
+                                   openTuner_cb _hidl_cb)  override;
+
+
+    // RefBase
+    virtual void onFirstRef();
+
+            Result  initCheck() { return mStatus; }
+            int closeHalTuner(const struct radio_tuner *halTuner);
+
+private:
+    virtual     ~BroadcastRadio();
+
+    static const char * sClassModuleNames[];
+
+    Result convertHalResult(int rc);
+    void convertBandConfigFromHal(BandConfig *config,
+            const radio_hal_band_config_t *halConfig);
+    void convertPropertiesFromHal(Properties *properties,
+            const radio_hal_properties_t *halProperties);
+    void convertBandConfigToHal(radio_hal_band_config_t *halConfig,
+            const BandConfig *config);
+
+    Result                   mStatus;
+    Class                    mClassId;
+    struct radio_hw_device  *mHwDevice;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HIDL_GENERATED_android_hardware_broadcastradio_V1_0_BroadcastRadio_H_
diff --git a/broadcastradio/1.0/default/BroadcastRadioFactory.cpp b/broadcastradio/1.0/default/BroadcastRadioFactory.cpp
new file mode 100644
index 0000000..d5d214c
--- /dev/null
+++ b/broadcastradio/1.0/default/BroadcastRadioFactory.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "BroadcastRadioFactory.h"
+#include "BroadcastRadio.h"
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory follow.
+Return<void> BroadcastRadioFactory::connectModule(Class classId, connectModule_cb _hidl_cb)  {
+    sp<BroadcastRadio> impl = new BroadcastRadio(classId);
+    Result retval = Result::NOT_INITIALIZED;
+    if (impl != 0) {
+        retval = impl->initCheck();
+    }
+    _hidl_cb(retval, impl);
+    return Void();
+}
+
+
+IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* /* name */) {
+    return new BroadcastRadioFactory();
+}
+
+} // namespace implementation
+}  // namespace V1_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/1.0/default/BroadcastRadioFactory.h b/broadcastradio/1.0/default/BroadcastRadioFactory.h
new file mode 100644
index 0000000..9b2ca17
--- /dev/null
+++ b/broadcastradio/1.0/default/BroadcastRadioFactory.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef HIDL_GENERATED_android_hardware_broadcastradio_V1_0_BroadcastRadioFactory_H_
+#define HIDL_GENERATED_android_hardware_broadcastradio_V1_0_BroadcastRadioFactory_H_
+
+#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+namespace implementation {
+
+struct BroadcastRadioFactory : public IBroadcastRadioFactory {
+    // Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory follow.
+    Return<void> connectModule(Class classId, connectModule_cb _hidl_cb)  override;
+
+};
+
+extern "C" IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HIDL_GENERATED_android_hardware_broadcastradio_V1_0_BroadcastRadioFactory_H_
diff --git a/broadcastradio/1.0/default/Tuner.cpp b/broadcastradio/1.0/default/Tuner.cpp
new file mode 100644
index 0000000..0c1d8ab
--- /dev/null
+++ b/broadcastradio/1.0/default/Tuner.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Tuner"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+
+#include "BroadcastRadio.h"
+#include "Tuner.h"
+#include "Utils.h"
+#include <system/radio_metadata.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+namespace implementation {
+
+void Tuner::onCallback(radio_hal_event_t *halEvent)
+{
+    BandConfig config;
+    ProgramInfo info;
+    hidl_vec<MetaData> metadata;
+
+    if (mCallback != 0) {
+        switch(halEvent->type) {
+        case RADIO_EVENT_CONFIG:
+            Utils::convertBandConfigFromHal(&config, &halEvent->config);
+            mCallback->configChange(Utils::convertHalResult(halEvent->status), config);
+            break;
+        case RADIO_EVENT_ANTENNA:
+            mCallback->antennaStateChange(halEvent->on);
+            break;
+        case RADIO_EVENT_TUNED:
+            Utils::convertProgramInfoFromHal(&info, &halEvent->info, true);
+            mCallback->tuneComplete(Utils::convertHalResult(halEvent->status), info);
+            break;
+        case RADIO_EVENT_METADATA: {
+            uint32_t channel;
+            uint32_t sub_channel;
+            if (radio_metadata_get_channel(halEvent->metadata, &channel, &sub_channel) == 0) {
+                Utils::convertMetaDataFromHal(metadata, halEvent->metadata);
+                mCallback->newMetadata(channel, sub_channel, metadata);
+            }
+            } break;
+        case RADIO_EVENT_TA:
+            mCallback->trafficAnnouncement(halEvent->on);
+            break;
+        case RADIO_EVENT_AF_SWITCH:
+            Utils::convertProgramInfoFromHal(&info, &halEvent->info, true);
+            mCallback->afSwitch(info);
+            break;
+        case RADIO_EVENT_EA:
+            mCallback->emergencyAnnouncement(halEvent->on);
+            break;
+        case RADIO_EVENT_HW_FAILURE:
+        default:
+            mCallback->hardwareFailure();
+            break;
+        }
+    }
+}
+
+//static
+void Tuner::callback(radio_hal_event_t *halEvent, void *cookie)
+{
+    wp<Tuner> weak(reinterpret_cast<Tuner*>(cookie));
+    sp<Tuner> tuner = weak.promote();
+    if (tuner == 0) return;
+    tuner->onCallback(halEvent);
+}
+
+Tuner::Tuner(const sp<ITunerCallback>& callback, const wp<BroadcastRadio>& parentDevice)
+    : mHalTuner(NULL), mCallback(callback), mParentDevice(parentDevice)
+{
+    ALOGV("%s", __FUNCTION__);
+}
+
+
+Tuner::~Tuner()
+{
+    ALOGV("%s", __FUNCTION__);
+    const sp<BroadcastRadio> parentDevice = mParentDevice.promote();
+    if (parentDevice != 0) {
+        parentDevice->closeHalTuner(mHalTuner);
+    }
+}
+
+// Methods from ::android::hardware::broadcastradio::V1_0::ITuner follow.
+Return<Result> Tuner::setConfiguration(const BandConfig& config)  {
+    ALOGV("%s", __FUNCTION__);
+    if (mHalTuner == NULL) {
+        return Utils::convertHalResult(-ENODEV);
+    }
+    radio_hal_band_config_t halConfig;
+    Utils::convertBandConfigToHal(&halConfig, &config);
+    int rc = mHalTuner->set_configuration(mHalTuner, &halConfig);
+    return Utils::convertHalResult(rc);
+}
+
+Return<void> Tuner::getConfiguration(getConfiguration_cb _hidl_cb)  {
+    int rc;
+    radio_hal_band_config_t halConfig;
+    BandConfig config;
+
+    ALOGV("%s", __FUNCTION__);
+    if (mHalTuner == NULL) {
+        rc = -ENODEV;
+        goto exit;
+    }
+    rc = mHalTuner->get_configuration(mHalTuner, &halConfig);
+    if (rc == 0) {
+        Utils::convertBandConfigFromHal(&config, &halConfig);
+    }
+
+exit:
+    _hidl_cb(Utils::convertHalResult(rc), config);
+    return Void();
+}
+
+Return<Result> Tuner::scan(Direction direction, bool skipSubChannel)  {
+    if (mHalTuner == NULL) {
+        return Utils::convertHalResult(-ENODEV);
+    }
+    int rc = mHalTuner->scan(mHalTuner, static_cast<radio_direction_t>(direction), skipSubChannel);
+    return Utils::convertHalResult(rc);
+}
+
+Return<Result> Tuner::step(Direction direction, bool skipSubChannel)  {
+    if (mHalTuner == NULL) {
+        return Utils::convertHalResult(-ENODEV);
+    }
+    int rc = mHalTuner->step(mHalTuner, static_cast<radio_direction_t>(direction), skipSubChannel);
+    return Utils::convertHalResult(rc);
+}
+
+Return<Result> Tuner::tune(uint32_t channel, uint32_t subChannel)  {
+    if (mHalTuner == NULL) {
+        return Utils::convertHalResult(-ENODEV);
+    }
+    int rc = mHalTuner->tune(mHalTuner, channel, subChannel);
+    return Utils::convertHalResult(rc);
+}
+
+Return<Result> Tuner::cancel()  {
+    if (mHalTuner == NULL) {
+        return Utils::convertHalResult(-ENODEV);
+    }
+    int rc = mHalTuner->cancel(mHalTuner);
+    return Utils::convertHalResult(rc);
+}
+
+Return<void> Tuner::getProgramInformation(bool withMetadata, getProgramInformation_cb _hidl_cb)  {
+    int rc;
+    radio_program_info_t halInfo;
+    ProgramInfo info;
+
+    ALOGV("%s", __FUNCTION__);
+    if (mHalTuner == NULL) {
+        rc = -ENODEV;
+        goto exit;
+    }
+    if (withMetadata) {
+        radio_metadata_allocate(&halInfo.metadata, 0, 0);
+    } else {
+        halInfo.metadata = NULL;
+    }
+    rc = mHalTuner->get_program_information(mHalTuner, &halInfo);
+    if (rc == 0) {
+        Utils::convertProgramInfoFromHal(&info, &halInfo, withMetadata);
+    }
+    if (withMetadata) {
+        radio_metadata_deallocate(halInfo.metadata);
+    }
+
+exit:
+    _hidl_cb(Utils::convertHalResult(rc), info);
+    return Void();
+}
+
+} // namespace implementation
+}  // namespace V1_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/1.0/default/Tuner.h b/broadcastradio/1.0/default/Tuner.h
new file mode 100644
index 0000000..94e216e
--- /dev/null
+++ b/broadcastradio/1.0/default/Tuner.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef HIDL_GENERATED_android_hardware_broadcastradio_V1_0_Tuner_H_
+#define HIDL_GENERATED_android_hardware_broadcastradio_V1_0_Tuner_H_
+
+#include <android/hardware/broadcastradio/1.0/ITuner.h>
+#include <android/hardware/broadcastradio/1.0/ITunerCallback.h>
+#include <hidl/Status.h>
+#include <hardware/radio.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+namespace implementation {
+
+struct BroadcastRadio;
+
+struct Tuner : public ITuner {
+
+    Tuner(const sp<ITunerCallback>& callback, const wp<BroadcastRadio>& mParentDevice);
+
+    // Methods from ::android::hardware::broadcastradio::V1_0::ITuner follow.
+    Return<Result> setConfiguration(const BandConfig& config)  override;
+    Return<void> getConfiguration(getConfiguration_cb _hidl_cb)  override;
+    Return<Result> scan(Direction direction, bool skipSubChannel)  override;
+    Return<Result> step(Direction direction, bool skipSubChannel)  override;
+    Return<Result> tune(uint32_t channel, uint32_t subChannel)  override;
+    Return<Result> cancel()  override;
+    Return<void> getProgramInformation(bool withMetadata,
+                                       getProgramInformation_cb _hidl_cb)  override;
+
+    static void callback(radio_hal_event_t *halEvent, void *cookie);
+           void onCallback(radio_hal_event_t *halEvent);
+
+    void setHalTuner(const struct radio_tuner *halTuner) { mHalTuner = halTuner; }
+    const struct radio_tuner *getHalTuner() { return mHalTuner; }
+
+ private:
+    ~Tuner();
+
+    const struct radio_tuner    *mHalTuner;
+    const sp<ITunerCallback>     mCallback;
+    const wp<BroadcastRadio>     mParentDevice;
+};
+
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HIDL_GENERATED_android_hardware_broadcastradio_V1_0_Tuner_H_
diff --git a/broadcastradio/1.0/default/Utils.cpp b/broadcastradio/1.0/default/Utils.cpp
new file mode 100644
index 0000000..bdaae00
--- /dev/null
+++ b/broadcastradio/1.0/default/Utils.cpp
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BroadcastRadioHalUtils"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/misc.h>
+#include <system/radio_metadata.h>
+
+#include "Utils.h"
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+namespace implementation {
+
+const char *Utils::sClassModuleNames[] = {
+    RADIO_HARDWARE_MODULE_ID_FM, /* corresponds to RADIO_CLASS_AM_FM */
+    RADIO_HARDWARE_MODULE_ID_SAT,  /* corresponds to RADIO_CLASS_SAT */
+    RADIO_HARDWARE_MODULE_ID_DT,   /* corresponds to RADIO_CLASS_DT */
+};
+
+// make sure HIDL enum values are aligned with legacy values
+static_assert(RADIO_CLASS_AM_FM == static_cast<int>(Class::AM_FM),
+              "AM/FM class mismatch with legacy");
+static_assert(RADIO_CLASS_SAT == static_cast<int>(Class::SAT),
+              "SAT class mismatch with legacy");
+static_assert(RADIO_CLASS_DT == static_cast<int>(Class::DT),
+              "DT class mismatch with legacy");
+
+static_assert(RADIO_BAND_AM == static_cast<int>(Band::AM),
+              "AM band mismatch with legacy");
+static_assert(RADIO_BAND_FM == static_cast<int>(Band::FM),
+              "FM band mismatch with legacy");
+static_assert(RADIO_BAND_AM_HD == static_cast<int>(Band::AM_HD),
+              "AM HD band mismatch with legacy");
+static_assert(RADIO_BAND_FM_HD == static_cast<int>(Band::FM_HD),
+              "FM HD band mismatch with legacy");
+
+static_assert(RADIO_RDS_NONE == static_cast<int>(Rds::NONE),
+              "RDS NONE mismatch with legacy");
+static_assert(RADIO_RDS_WORLD == static_cast<int>(Rds::WORLD),
+              "RDS WORLD mismatch with legacy");
+static_assert(RADIO_RDS_US == static_cast<int>(Rds::US),
+              "RDS US mismatch with legacy");
+
+static_assert(RADIO_DEEMPHASIS_50 == static_cast<int>(Deemphasis::D50),
+              "De-emphasis 50 mismatch with legacy");
+static_assert(RADIO_DEEMPHASIS_75 == static_cast<int>(Deemphasis::D75),
+              "De-emphasis 75 mismatch with legacy");
+
+static_assert(RADIO_DIRECTION_UP == static_cast<int>(Direction::UP),
+              "Direction Up mismatch with legacy");
+static_assert(RADIO_DIRECTION_DOWN == static_cast<int>(Direction::DOWN),
+              "Direction Up mismatch with legacy");
+
+static_assert(RADIO_METADATA_TYPE_INVALID == static_cast<int>(MetadataType::INVALID),
+              "Metadata type INVALID mismatch with legacy");
+static_assert(RADIO_METADATA_TYPE_INT == static_cast<int>(MetadataType::INT),
+              "Metadata type INT mismatch with legacy");
+static_assert(RADIO_METADATA_TYPE_TEXT == static_cast<int>(MetadataType::TEXT),
+              "Metadata type TEXT mismatch with legacy");
+static_assert(RADIO_METADATA_TYPE_RAW == static_cast<int>(MetadataType::RAW),
+              "Metadata type RAW mismatch with legacy");
+static_assert(RADIO_METADATA_TYPE_CLOCK == static_cast<int>(MetadataType::CLOCK),
+              "Metadata type CLOCK mismatch with legacy");
+
+static_assert(RADIO_METADATA_KEY_INVALID == static_cast<int>(MetadataKey::INVALID),
+              "Metadata key INVALID mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_RDS_PI == static_cast<int>(MetadataKey::RDS_PI),
+              "Metadata key RDS_PI mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_RDS_PS == static_cast<int>(MetadataKey::RDS_PS),
+              "Metadata key RDS_PS mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_RDS_PTY == static_cast<int>(MetadataKey::RDS_PTY),
+              "Metadata key RDS_PTY mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_RBDS_PTY == static_cast<int>(MetadataKey::RBDS_PTY),
+              "Metadata key RBDS_PTY mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_RDS_RT == static_cast<int>(MetadataKey::RDS_RT),
+              "Metadata key RDS_RT mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_TITLE == static_cast<int>(MetadataKey::TITLE),
+              "Metadata key TITLE mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_ARTIST == static_cast<int>(MetadataKey::ARTIST),
+              "Metadata key ARTIST mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_ALBUM == static_cast<int>(MetadataKey::ALBUM),
+              "Metadata key ALBUM mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_GENRE == static_cast<int>(MetadataKey::GENRE),
+              "Metadata key GENRE mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_ICON == static_cast<int>(MetadataKey::ICON),
+              "Metadata key ICON mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_ART == static_cast<int>(MetadataKey::ART),
+              "Metadata key ART mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_CLOCK == static_cast<int>(MetadataKey::CLOCK),
+              "Metadata key CLOCK mismatch with legacy");
+
+
+//static
+const char * Utils::getClassString(Class ClassId)
+{
+    int id = static_cast<int>(ClassId);
+
+    if ((id < 0) ||
+            (id >= NELEM(sClassModuleNames))) {
+        ALOGE("invalid class ID %d", id);
+        return NULL;
+    }
+    return sClassModuleNames[id];
+}
+
+//static
+Result Utils::convertHalResult(int rc)
+{
+    switch (rc) {
+        case 0:
+            return Result::OK;
+        case -EINVAL:
+            return Result::INVALID_ARGUMENTS;
+        case -ENOSYS:
+            return Result::INVALID_STATE;
+        case -ETIMEDOUT:
+            return Result::TIMEOUT;
+        case -ENODEV:
+        default:
+            return Result::NOT_INITIALIZED;
+    }
+}
+
+//static
+void Utils::convertBandConfigFromHal(
+        BandConfig *config,
+        const radio_hal_band_config_t *halConfig)
+{
+
+    config->type = static_cast<Band>(halConfig->type);
+    config->antennaConnected = halConfig->antenna_connected;
+    config->lowerLimit = halConfig->lower_limit;
+    config->upperLimit = halConfig->upper_limit;
+    config->spacings.setToExternal(const_cast<unsigned int *>(&halConfig->spacings[0]),
+                                       halConfig->num_spacings * sizeof(uint32_t));
+    // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+    config->spacings.resize(halConfig->num_spacings);
+
+    if (config->type == Band::FM) {
+        config->ext.fm.deemphasis = static_cast<Deemphasis>(halConfig->fm.deemphasis);
+        config->ext.fm.stereo = halConfig->fm.stereo;
+        config->ext.fm.rds = static_cast<Rds>(halConfig->fm.rds);
+        config->ext.fm.ta = halConfig->fm.ta;
+        config->ext.fm.af = halConfig->fm.af;
+        config->ext.fm.ea = halConfig->fm.ea;
+    } else {
+        config->ext.am.stereo = halConfig->am.stereo;
+    }
+}
+
+//static
+void Utils::convertPropertiesFromHal(
+        Properties *properties,
+        const radio_hal_properties_t *halProperties)
+{
+    properties->classId = static_cast<Class>(halProperties->class_id);
+    properties->implementor.setToExternal(halProperties->implementor, strlen(halProperties->implementor));
+    properties->product.setToExternal(halProperties->product, strlen(halProperties->product));
+    properties->version.setToExternal(halProperties->version, strlen(halProperties->version));
+    properties->serial.setToExternal(halProperties->serial, strlen(halProperties->serial));
+    properties->numTuners = halProperties->num_tuners;
+    properties->numAudioSources = halProperties->num_audio_sources;
+    properties->supportsCapture = halProperties->supports_capture;
+
+    BandConfig *bands =
+            new BandConfig[halProperties->num_bands];
+    for (size_t i = 0; i < halProperties->num_bands; i++) {
+        convertBandConfigFromHal(&bands[i], &halProperties->bands[i]);
+    }
+    properties->bands.setToExternal(bands, halProperties->num_bands);
+    // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+    properties->bands.resize(halProperties->num_bands);
+    delete[] bands;
+}
+
+//static
+void Utils::convertBandConfigToHal(
+        radio_hal_band_config_t *halConfig,
+        const BandConfig *config)
+{
+
+    halConfig->type = static_cast<radio_band_t>(config->type);
+    halConfig->antenna_connected = config->antennaConnected;
+    halConfig->lower_limit = config->lowerLimit;
+    halConfig->upper_limit = config->upperLimit;
+    halConfig->num_spacings = config->spacings.size();
+    if (halConfig->num_spacings > RADIO_NUM_SPACINGS_MAX) {
+        halConfig->num_spacings = RADIO_NUM_SPACINGS_MAX;
+    }
+    memcpy(halConfig->spacings, config->spacings.data(),
+           sizeof(uint32_t) * halConfig->num_spacings);
+
+    if (config->type == Band::FM) {
+        halConfig->fm.deemphasis = static_cast<radio_deemphasis_t>(config->ext.fm.deemphasis);
+        halConfig->fm.stereo = config->ext.fm.stereo;
+        halConfig->fm.rds = static_cast<radio_rds_t>(config->ext.fm.rds);
+        halConfig->fm.ta = config->ext.fm.ta;
+        halConfig->fm.af = config->ext.fm.af;
+        halConfig->fm.ea = config->ext.fm.ea;
+    } else {
+        halConfig->am.stereo = config->ext.am.stereo;
+    }
+}
+
+
+//static
+void Utils::convertProgramInfoFromHal(ProgramInfo *info,
+                                      radio_program_info_t *halInfo,
+                                      bool withMetadata)
+{
+    info->channel = halInfo->channel;
+    info->subChannel = halInfo->sub_channel;
+    info->tuned = halInfo->tuned;
+    info->stereo = halInfo->stereo;
+    info->digital = halInfo->digital;
+    info->signalStrength = halInfo->signal_strength;
+    if (withMetadata && halInfo->metadata != NULL) {
+        convertMetaDataFromHal(info->metadata, halInfo->metadata);
+    }
+}
+
+//static
+int Utils::convertMetaDataFromHal(hidl_vec<MetaData>& metadata,
+                                   radio_metadata_t *halMetadata)
+{
+    if (halMetadata == NULL) {
+        return 0;
+    }
+
+    int count = radio_metadata_get_count(halMetadata);
+    if (count <= 0) {
+        return count;
+    }
+    MetaData *newMetadata =
+            new MetaData[count];
+    int outCount = 0;
+    for (int i = 0; i < count; i++) {
+        radio_metadata_key_t key;
+        radio_metadata_type_t type;
+        void *value;
+        size_t size;
+        if (radio_metadata_get_at_index(halMetadata, i , &key, &type, &value, &size) != 0 ||
+                size == 0) {
+            continue;
+        }
+        switch (type) {
+            case RADIO_METADATA_TYPE_INT: {
+                newMetadata[outCount].intValue = *(static_cast<int32_t *>(value));
+            } break;
+            case RADIO_METADATA_TYPE_TEXT: {
+                newMetadata[outCount].stringValue = static_cast<char *>(value);
+            } break;
+            case RADIO_METADATA_TYPE_RAW: {
+                newMetadata[outCount].rawValue.setToExternal(static_cast<uint8_t *>(value), size);
+                // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+                newMetadata[outCount].rawValue.resize(size);
+            } break;
+            case RADIO_METADATA_TYPE_CLOCK: {
+                  radio_metadata_clock_t *clock = static_cast<radio_metadata_clock_t *>(value);
+                  newMetadata[outCount].clockValue.utcSecondsSinceEpoch =
+                          clock->utc_seconds_since_epoch;
+                  newMetadata[outCount].clockValue.timezoneOffsetInMinutes =
+                          clock->timezone_offset_in_minutes;
+            } break;
+        }
+        newMetadata[outCount].type = static_cast<MetadataType>(type);
+        newMetadata[outCount].key = static_cast<MetadataKey>(key);
+        outCount++;
+    }
+    metadata.setToExternal(newMetadata, outCount);
+    // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+    metadata.resize(outCount);
+    return outCount;
+}
+
+} // namespace implementation
+}  // namespace V1_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/1.0/default/Utils.h b/broadcastradio/1.0/default/Utils.h
new file mode 100644
index 0000000..25eb6ee
--- /dev/null
+++ b/broadcastradio/1.0/default/Utils.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_0_UTILS_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_0_UTILS_H
+
+#include <android/hardware/broadcastradio/1.0/types.h>
+#include <hardware/radio.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+namespace implementation {
+
+class Utils {
+public:
+    static const char * getClassString(Class ClassId);
+    static Result convertHalResult(int rc);
+    static void convertBandConfigFromHal(BandConfig *config,
+            const radio_hal_band_config_t *halConfig);
+    static void convertPropertiesFromHal(Properties *properties,
+            const radio_hal_properties_t *halProperties);
+    static void convertBandConfigToHal(radio_hal_band_config_t *halConfig,
+            const BandConfig *config);
+    static void convertProgramInfoFromHal(ProgramInfo *info,
+                                          radio_program_info_t *halInfo,
+                                          bool withMetadata);
+    static int convertMetaDataFromHal(hidl_vec<MetaData>& metadata,
+                                       radio_metadata_t *halMetadata);
+private:
+    static const char * sClassModuleNames[];
+
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_0_UTILS_H
diff --git a/broadcastradio/1.0/types.hal b/broadcastradio/1.0/types.hal
index c5b4411..d04359c 100644
--- a/broadcastradio/1.0/types.hal
+++ b/broadcastradio/1.0/types.hal
@@ -54,7 +54,7 @@
 enum Rds : uint32_t {
     NONE   = 0,
     WORLD  = (1<<0),
-    RDS_US = (1<<1),
+    US = (1<<1),
 };
 
 
@@ -111,7 +111,7 @@
     union Ext {
         FmBandConfig fm;
         AmBandConfig am;
-    };
+    } ext;
 };
 
 /* Exposes properties of a given hardware radio module.
diff --git a/graphics/Android.bp b/graphics/Android.bp
index 4ac7766..796ef41 100644
--- a/graphics/Android.bp
+++ b/graphics/Android.bp
@@ -2,6 +2,7 @@
 subdirs = [
     "allocator/2.0",
     "allocator/2.0/default",
+    "allocator/2.0/vts/functional",
     "common/1.0",
     "composer/2.1",
     "composer/2.1/default",
diff --git a/graphics/allocator/2.0/IAllocator.hal b/graphics/allocator/2.0/IAllocator.hal
index 0464bcd..9a45444 100644
--- a/graphics/allocator/2.0/IAllocator.hal
+++ b/graphics/allocator/2.0/IAllocator.hal
@@ -78,6 +78,9 @@
      *
      * @return capabilities is a list of supported capabilities.
      */
+    @entry
+    @exit
+    @callflow(next="*")
     getCapabilities() generates (vec<Capability> capabilities);
 
     /*
@@ -86,6 +89,9 @@
      *
      * @return debugInfo is a string of debug information.
      */
+    @entry
+    @exit
+    @callflow(next="*")
     dumpDebugInfo() generates (string debugInfo);
 
     /*
@@ -98,6 +104,8 @@
      *         NO_RESOURCES when no more descriptors can currently be created.
      * @return descriptor is the newly created buffer descriptor.
      */
+    @entry
+    @callflow(next="*")
     createDescriptor(BufferDescriptorInfo descriptorInfo)
           generates (Error error,
                      BufferDescriptor descriptor);
@@ -108,6 +116,8 @@
      * @param descriptor is the descriptor to destroy.
      * @return error is either NONE or BAD_DESCRIPTOR.
      */
+    @exit
+    @callflow(next="*")
     destroyDescriptor(BufferDescriptor descriptor) generates (Error error);
 
     /*
@@ -124,6 +134,7 @@
      *         UNSUPPORTED when any of the descriptors can never be satisfied.
      *         UNDEFINED when TEST_ALLOCATE is not listed in getCapabilities.
      */
+    @callflow(next="allocate")
     testAllocate(vec<BufferDescriptor> descriptors) generates (Error error);
 
     /*
@@ -147,6 +158,7 @@
      *                      time.
      * @return buffers is the allocated buffers.
      */
+    @callflow(next="exportHandle")
     allocate(vec<BufferDescriptor> descriptors)
         generates (Error error,
                    vec<Buffer> buffers);
@@ -158,6 +170,8 @@
      * @return error is NONE upon success. Otherwise,
      *         BAD_BUFFER when the buffer is invalid.
      */
+    @exit
+    @callflow(next="*")
     free(Buffer buffer) generates (Error error);
 
     /*
@@ -182,6 +196,7 @@
      *         NO_RESOURCES when the buffer cannot be exported at this time.
      * @return bufferHandle is the exported handle.
      */
+    @callflow(next="free")
     exportHandle(BufferDescriptor descriptor,
                  Buffer buffer)
       generates (Error error,
diff --git a/graphics/allocator/2.0/vts/Allocator.vts b/graphics/allocator/2.0/vts/Allocator.vts
new file mode 100644
index 0000000..04d4314
--- /dev/null
+++ b/graphics/allocator/2.0/vts/Allocator.vts
@@ -0,0 +1,215 @@
+component_class: HAL_HIDL
+component_type_version: 2.0
+component_name: "IAllocator"
+
+package: "android.hardware.graphics.allocator"
+
+import: "android.hardware.graphics.allocator@2.0::types"
+
+interface: {
+    attribute: {
+        name: "::android::hardware::graphics::allocator::V2_0::IAllocator::Capability"
+        type: TYPE_ENUM
+        enum_value: {
+            scalar_type: "int32_t"
+
+            enumerator: "INVALID"
+            scalar_value: {
+                int32_t: 0
+            }
+            enumerator: "TEST_ALLOCATE"
+            scalar_value: {
+                int32_t: 1
+            }
+        }
+    }
+
+    attribute: {
+        name: "::android::hardware::graphics::allocator::V2_0::IAllocator::BufferDescriptorInfo"
+        type: TYPE_STRUCT
+        struct_value: {
+            name: "width"
+            type: TYPE_SCALAR
+            scalar_type: "uint32_t"
+        }
+        struct_value: {
+            name: "height"
+            type: TYPE_SCALAR
+            scalar_type: "uint32_t"
+        }
+        struct_value: {
+            name: "format"
+            type: TYPE_ENUM
+            predefined_type: "::android::hardware::graphics::allocator::V2_0::PixelFormat"
+        }
+        struct_value: {
+            name: "producerUsageMask"
+            type: TYPE_SCALAR
+            scalar_type: "uint64_t"
+        }
+        struct_value: {
+            name: "consumerUsageMask"
+            type: TYPE_SCALAR
+            scalar_type: "uint64_t"
+        }
+    }
+
+    api: {
+        name: "getCapabilities"
+        return_type_hidl: {
+            type: TYPE_VECTOR
+            vector_value: {
+                type: TYPE_ENUM
+                predefined_type: "::android::hardware::graphics::allocator::V2_0::IAllocator::Capability"
+            }
+        }
+        callflow: {
+            entry: true
+        }
+        callflow: {
+            exit: true
+        }
+        callflow: {
+            next: "*"
+        }
+    }
+
+    api: {
+        name: "dumpDebugInfo"
+        return_type_hidl: {
+            type: TYPE_STRING
+        }
+        callflow: {
+            entry: true
+        }
+        callflow: {
+            exit: true
+        }
+        callflow: {
+            next: "*"
+        }
+    }
+
+    api: {
+        name: "createDescriptor"
+        return_type_hidl: {
+            type: TYPE_ENUM
+            predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+        }
+        return_type_hidl: {
+            type: TYPE_SCALAR
+            scalar_type: "uint64_t"
+        }
+        arg: {
+            type: TYPE_STRUCT
+            predefined_type: "::android::hardware::graphics::allocator::V2_0::IAllocator::BufferDescriptorInfo"
+        }
+        callflow: {
+            entry: true
+        }
+        callflow: {
+            next: "*"
+        }
+    }
+
+    api: {
+        name: "destroyDescriptor"
+        return_type_hidl: {
+            type: TYPE_ENUM
+            predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+        }
+        arg: {
+            type: TYPE_SCALAR
+            scalar_type: "uint64_t"
+        }
+        callflow: {
+            exit: true
+        }
+        callflow: {
+            next: "*"
+        }
+    }
+
+    api: {
+        name: "testAllocate"
+        return_type_hidl: {
+            type: TYPE_ENUM
+            predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+        }
+        arg: {
+            type: TYPE_VECTOR
+            vector_value: {
+                type: TYPE_SCALAR
+                scalar_type: "uint64_t"
+            }
+        }
+        callflow: {
+            next: "allocate"
+        }
+    }
+
+    api: {
+        name: "allocate"
+        return_type_hidl: {
+            type: TYPE_ENUM
+            predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+        }
+        return_type_hidl: {
+            type: TYPE_VECTOR
+            vector_value: {
+                type: TYPE_SCALAR
+                scalar_type: "uint64_t"
+            }
+        }
+        arg: {
+            type: TYPE_VECTOR
+            vector_value: {
+                type: TYPE_SCALAR
+                scalar_type: "uint64_t"
+            }
+        }
+        callflow: {
+            next: "exportHandle"
+        }
+    }
+
+    api: {
+        name: "free"
+        return_type_hidl: {
+            type: TYPE_ENUM
+            predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+        }
+        arg: {
+            type: TYPE_SCALAR
+            scalar_type: "uint64_t"
+        }
+        callflow: {
+            exit: true
+        }
+        callflow: {
+            next: "*"
+        }
+    }
+
+    api: {
+        name: "exportHandle"
+        return_type_hidl: {
+            type: TYPE_ENUM
+            predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+        }
+        return_type_hidl: {
+        }
+        arg: {
+            type: TYPE_SCALAR
+            scalar_type: "uint64_t"
+        }
+        arg: {
+            type: TYPE_SCALAR
+            scalar_type: "uint64_t"
+        }
+        callflow: {
+            next: "free"
+        }
+    }
+
+}
diff --git a/graphics/allocator/2.0/vts/functional/Android.bp b/graphics/allocator/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..e1966dc
--- /dev/null
+++ b/graphics/allocator/2.0/vts/functional/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "graphics_allocator_hidl_hal_test",
+    gtest: true,
+    srcs: ["graphics_allocator_hidl_hal_test.cpp"],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libcutils",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libnativehelper",
+        "libutils",
+        "android.hardware.graphics.allocator@2.0",
+    ],
+    static_libs: ["libgtest"],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
diff --git a/graphics/allocator/2.0/vts/functional/graphics_allocator_hidl_hal_test.cpp b/graphics/allocator/2.0/vts/functional/graphics_allocator_hidl_hal_test.cpp
new file mode 100644
index 0000000..54369a4
--- /dev/null
+++ b/graphics/allocator/2.0/vts/functional/graphics_allocator_hidl_hal_test.cpp
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "graphics_allocator_hidl_hal_test"
+
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace tests {
+namespace {
+
+using android::hardware::graphics::common::V1_0::PixelFormat;
+
+#define CHECK_FEATURE_OR_SKIP(FEATURE_NAME)                 \
+  do {                                                      \
+    if (!hasCapability(FEATURE_NAME)) {                     \
+      std::cout << "[  SKIPPED ] Feature " << #FEATURE_NAME \
+                << " not supported" << std::endl;           \
+      return;                                               \
+    }                                                       \
+  } while (0)
+
+class TempDescriptor {
+ public:
+  TempDescriptor(const sp<IAllocator>& allocator,
+                 const IAllocator::BufferDescriptorInfo& info)
+      : mAllocator(allocator), mError(Error::NO_RESOURCES) {
+    mAllocator->createDescriptor(
+        info, [&](const auto& tmpError, const auto& tmpDescriptor) {
+          mError = tmpError;
+          mDescriptor = tmpDescriptor;
+        });
+  }
+
+  ~TempDescriptor() {
+    if (mError == Error::NONE) {
+      mAllocator->destroyDescriptor(mDescriptor);
+    }
+  }
+
+  bool isValid() const { return (mError == Error::NONE); }
+
+  operator BufferDescriptor() const { return mDescriptor; }
+
+ private:
+  sp<IAllocator> mAllocator;
+  Error mError;
+  BufferDescriptor mDescriptor;
+};
+
+class GraphicsAllocatorHidlTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    mAllocator = IAllocator::getService("gralloc");
+    ASSERT_NE(mAllocator, nullptr);
+
+    initCapabilities();
+
+    mDummyDescriptorInfo.width = 64;
+    mDummyDescriptorInfo.height = 64;
+    mDummyDescriptorInfo.format = PixelFormat::RGBA_8888;
+    mDummyDescriptorInfo.producerUsageMask =
+        static_cast<uint64_t>(ProducerUsage::CPU_WRITE);
+    mDummyDescriptorInfo.consumerUsageMask =
+        static_cast<uint64_t>(ConsumerUsage::CPU_READ);
+  }
+
+  void TearDown() override {}
+
+  /**
+   * Initialize the set of supported capabilities.
+   */
+  void initCapabilities() {
+    mAllocator->getCapabilities([this](const auto& capabilities) {
+      std::vector<IAllocator::Capability> caps = capabilities;
+      mCapabilities.insert(caps.cbegin(), caps.cend());
+    });
+  }
+
+  /**
+   * Test whether a capability is supported.
+   */
+  bool hasCapability(IAllocator::Capability capability) const {
+    return (mCapabilities.count(capability) > 0);
+  }
+
+  sp<IAllocator> mAllocator;
+  IAllocator::BufferDescriptorInfo mDummyDescriptorInfo{};
+
+ private:
+  std::unordered_set<IAllocator::Capability> mCapabilities;
+};
+
+TEST_F(GraphicsAllocatorHidlTest, GetCapabilities) {
+  auto ret = mAllocator->getCapabilities([](const auto& capabilities) {
+    std::vector<IAllocator::Capability> caps = capabilities;
+    for (auto cap : caps) {
+      EXPECT_NE(IAllocator::Capability::INVALID, cap);
+    }
+  });
+
+  ASSERT_TRUE(ret.getStatus().isOk());
+}
+
+TEST_F(GraphicsAllocatorHidlTest, DumpDebugInfo) {
+  auto ret = mAllocator->dumpDebugInfo([](const auto&) {
+    // nothing to do
+  });
+
+  ASSERT_TRUE(ret.getStatus().isOk());
+}
+
+TEST_F(GraphicsAllocatorHidlTest, CreateDestroyDescriptor) {
+  Error error;
+  BufferDescriptor descriptor;
+  auto ret = mAllocator->createDescriptor(
+      mDummyDescriptorInfo,
+      [&](const auto& tmpError, const auto& tmpDescriptor) {
+        error = tmpError;
+        descriptor = tmpDescriptor;
+      });
+
+  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_EQ(Error::NONE, error);
+
+  auto err_ret = mAllocator->destroyDescriptor(descriptor);
+  ASSERT_TRUE(err_ret.getStatus().isOk());
+  ASSERT_EQ(Error::NONE, static_cast<Error>(err_ret));
+}
+
+/**
+ * Test testAllocate with a single buffer descriptor.
+ */
+TEST_F(GraphicsAllocatorHidlTest, TestAllocateBasic) {
+  CHECK_FEATURE_OR_SKIP(IAllocator::Capability::TEST_ALLOCATE);
+
+  TempDescriptor descriptor(mAllocator, mDummyDescriptorInfo);
+  ASSERT_TRUE(descriptor.isValid());
+
+  hidl_vec<BufferDescriptor> descriptors;
+  descriptors.resize(1);
+  descriptors[0] = descriptor;
+
+  auto ret = mAllocator->testAllocate(descriptors);
+  ASSERT_TRUE(ret.getStatus().isOk());
+
+  auto error = static_cast<Error>(ret);
+  ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED);
+}
+
+/**
+ * Test testAllocate with two buffer descriptors.
+ */
+TEST_F(GraphicsAllocatorHidlTest, TestAllocateArray) {
+  CHECK_FEATURE_OR_SKIP(IAllocator::Capability::TEST_ALLOCATE);
+
+  TempDescriptor descriptor(mAllocator, mDummyDescriptorInfo);
+  ASSERT_TRUE(descriptor.isValid());
+
+  hidl_vec<BufferDescriptor> descriptors;
+  descriptors.resize(2);
+  descriptors[0] = descriptor;
+  descriptors[1] = descriptor;
+
+  auto ret = mAllocator->testAllocate(descriptors);
+  ASSERT_TRUE(ret.getStatus().isOk());
+
+  auto error = static_cast<Error>(ret);
+  ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED);
+}
+
+/**
+ * Test allocate/free with a single buffer descriptor.
+ */
+TEST_F(GraphicsAllocatorHidlTest, AllocateFreeBasic) {
+  TempDescriptor descriptor(mAllocator, mDummyDescriptorInfo);
+  ASSERT_TRUE(descriptor.isValid());
+
+  hidl_vec<BufferDescriptor> descriptors;
+  descriptors.resize(1);
+  descriptors[0] = descriptor;
+
+  Error error;
+  std::vector<Buffer> buffers;
+  auto ret = mAllocator->allocate(
+      descriptors, [&](const auto& tmpError, const auto& tmpBuffers) {
+        error = tmpError;
+        buffers = tmpBuffers;
+      });
+
+  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED);
+  EXPECT_EQ(1u, buffers.size());
+
+  if (!buffers.empty()) {
+    auto err_ret = mAllocator->free(buffers[0]);
+    EXPECT_TRUE(err_ret.getStatus().isOk());
+    EXPECT_EQ(Error::NONE, static_cast<Error>(err_ret));
+  }
+}
+
+/**
+ * Test allocate/free with an array of buffer descriptors.
+ */
+TEST_F(GraphicsAllocatorHidlTest, AllocateFreeArray) {
+  TempDescriptor descriptor1(mAllocator, mDummyDescriptorInfo);
+  ASSERT_TRUE(descriptor1.isValid());
+
+  TempDescriptor descriptor2(mAllocator, mDummyDescriptorInfo);
+  ASSERT_TRUE(descriptor2.isValid());
+
+  hidl_vec<BufferDescriptor> descriptors;
+  descriptors.resize(3);
+  descriptors[0] = descriptor1;
+  descriptors[1] = descriptor1;
+  descriptors[2] = descriptor2;
+
+  Error error;
+  std::vector<Buffer> buffers;
+  auto ret = mAllocator->allocate(
+      descriptors, [&](const auto& tmpError, const auto& tmpBuffers) {
+        error = tmpError;
+        buffers = tmpBuffers;
+      });
+
+  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED);
+  EXPECT_EQ(descriptors.size(), buffers.size());
+
+  for (auto buf : buffers) {
+    auto err_ret = mAllocator->free(buf);
+    EXPECT_TRUE(err_ret.getStatus().isOk());
+    EXPECT_EQ(Error::NONE, static_cast<Error>(err_ret));
+  }
+}
+
+TEST_F(GraphicsAllocatorHidlTest, ExportHandle) {
+  TempDescriptor descriptor(mAllocator, mDummyDescriptorInfo);
+  ASSERT_TRUE(descriptor.isValid());
+
+  hidl_vec<BufferDescriptor> descriptors;
+  descriptors.resize(1);
+  descriptors[0] = descriptor;
+
+  Error error;
+  std::vector<Buffer> buffers;
+  auto ret = mAllocator->allocate(
+      descriptors, [&](const auto& tmpError, const auto& tmpBuffers) {
+        error = tmpError;
+        buffers = tmpBuffers;
+      });
+
+  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED);
+  ASSERT_EQ(1u, buffers.size());
+
+  ret = mAllocator->exportHandle(
+      descriptors[0], buffers[0],
+      [&](const auto& tmpError, const auto&) { error = tmpError; });
+  EXPECT_TRUE(ret.getStatus().isOk());
+  EXPECT_EQ(Error::NONE, error);
+
+  auto err_ret = mAllocator->free(buffers[0]);
+  EXPECT_TRUE(err_ret.getStatus().isOk());
+  EXPECT_EQ(Error::NONE, static_cast<Error>(err_ret));
+}
+
+}  // namespace anonymous
+}  // namespace tests
+}  // namespace V2_0
+}  // namespace allocator
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+
+  int status = RUN_ALL_TESTS();
+  ALOGI("Test result = %d", status);
+
+  return status;
+}
diff --git a/graphics/allocator/2.0/vts/types.vts b/graphics/allocator/2.0/vts/types.vts
new file mode 100644
index 0000000..ac1bf3f
--- /dev/null
+++ b/graphics/allocator/2.0/vts/types.vts
@@ -0,0 +1,231 @@
+component_class: HAL_HIDL
+component_type_version: 2.0
+component_name: "types"
+
+package: "android.hardware.graphics.allocator"
+
+
+attribute: {
+    name: "::android::hardware::graphics::allocator::V2_0::Error"
+    type: TYPE_ENUM
+    enum_value: {
+        scalar_type: "int32_t"
+
+        enumerator: "NONE"
+        scalar_value: {
+            int32_t: 0
+        }
+        enumerator: "BAD_DESCRIPTOR"
+        scalar_value: {
+            int32_t: 1
+        }
+        enumerator: "BAD_BUFFER"
+        scalar_value: {
+            int32_t: 2
+        }
+        enumerator: "BAD_VALUE"
+        scalar_value: {
+            int32_t: 3
+        }
+        enumerator: "NOT_SHARED"
+        scalar_value: {
+            int32_t: 4
+        }
+        enumerator: "NO_RESOURCES"
+        scalar_value: {
+            int32_t: 5
+        }
+        enumerator: "UNDEFINED"
+        scalar_value: {
+            int32_t: 6
+        }
+        enumerator: "UNSUPPORTED"
+        scalar_value: {
+            int32_t: 7
+        }
+    }
+}
+
+attribute: {
+    name: "::android::hardware::graphics::allocator::V2_0::ProducerUsage"
+    type: TYPE_ENUM
+    enum_value: {
+        scalar_type: "uint64_t"
+
+        enumerator: "CPU_READ"
+        scalar_value: {
+            uint64_t: 2
+        }
+        enumerator: "CPU_READ_OFTEN"
+        scalar_value: {
+            uint64_t: 4
+        }
+        enumerator: "CPU_WRITE"
+        scalar_value: {
+            uint64_t: 32
+        }
+        enumerator: "CPU_WRITE_OFTEN"
+        scalar_value: {
+            uint64_t: 64
+        }
+        enumerator: "GPU_RENDER_TARGET"
+        scalar_value: {
+            uint64_t: 512
+        }
+        enumerator: "PROTECTED"
+        scalar_value: {
+            uint64_t: 16384
+        }
+        enumerator: "CAMERA"
+        scalar_value: {
+            uint64_t: 131072
+        }
+        enumerator: "VIDEO_DECODER"
+        scalar_value: {
+            uint64_t: 4194304
+        }
+    }
+}
+
+attribute: {
+    name: "::android::hardware::graphics::allocator::V2_0::ConsumerUsage"
+    type: TYPE_ENUM
+    enum_value: {
+        scalar_type: "uint64_t"
+
+        enumerator: "CPU_READ"
+        scalar_value: {
+            uint64_t: 2
+        }
+        enumerator: "CPU_READ_OFTEN"
+        scalar_value: {
+            uint64_t: 4
+        }
+        enumerator: "GPU_TEXTURE"
+        scalar_value: {
+            uint64_t: 256
+        }
+        enumerator: "HWCOMPOSER"
+        scalar_value: {
+            uint64_t: 2048
+        }
+        enumerator: "CLIENT_TARGET"
+        scalar_value: {
+            uint64_t: 4096
+        }
+        enumerator: "CURSOR"
+        scalar_value: {
+            uint64_t: 32768
+        }
+        enumerator: "VIDEO_ENCODER"
+        scalar_value: {
+            uint64_t: 65536
+        }
+        enumerator: "CAMERA"
+        scalar_value: {
+            uint64_t: 262144
+        }
+        enumerator: "RENDERSCRIPT"
+        scalar_value: {
+            uint64_t: 1048576
+        }
+    }
+}
+
+attribute: {
+    name: "::android::hardware::graphics::allocator::V2_0::PixelFormat"
+    type: TYPE_ENUM
+    enum_value: {
+        scalar_type: "int32_t"
+
+        enumerator: "RGBA_8888"
+        scalar_value: {
+            int32_t: 1
+        }
+        enumerator: "RGBX_8888"
+        scalar_value: {
+            int32_t: 2
+        }
+        enumerator: "RGB_888"
+        scalar_value: {
+            int32_t: 3
+        }
+        enumerator: "RGB_565"
+        scalar_value: {
+            int32_t: 4
+        }
+        enumerator: "BGRA_8888"
+        scalar_value: {
+            int32_t: 5
+        }
+        enumerator: "YV12"
+        scalar_value: {
+            int32_t: 842094169
+        }
+        enumerator: "Y8"
+        scalar_value: {
+            int32_t: 538982489
+        }
+        enumerator: "Y16"
+        scalar_value: {
+            int32_t: 540422489
+        }
+        enumerator: "RAW16"
+        scalar_value: {
+            int32_t: 32
+        }
+        enumerator: "RAW10"
+        scalar_value: {
+            int32_t: 37
+        }
+        enumerator: "RAW12"
+        scalar_value: {
+            int32_t: 38
+        }
+        enumerator: "RAW_OPAQUE"
+        scalar_value: {
+            int32_t: 36
+        }
+        enumerator: "BLOB"
+        scalar_value: {
+            int32_t: 33
+        }
+        enumerator: "IMPLEMENTATION_DEFINED"
+        scalar_value: {
+            int32_t: 34
+        }
+        enumerator: "YCbCr_420_888"
+        scalar_value: {
+            int32_t: 35
+        }
+        enumerator: "YCbCr_422_888"
+        scalar_value: {
+            int32_t: 39
+        }
+        enumerator: "YCbCr_444_888"
+        scalar_value: {
+            int32_t: 40
+        }
+        enumerator: "FLEX_RGB_888"
+        scalar_value: {
+            int32_t: 41
+        }
+        enumerator: "FLEX_RGBA_8888"
+        scalar_value: {
+            int32_t: 42
+        }
+        enumerator: "YCbCr_422_SP"
+        scalar_value: {
+            int32_t: 16
+        }
+        enumerator: "YCrCb_420_SP"
+        scalar_value: {
+            int32_t: 17
+        }
+        enumerator: "YCbCr_422_I"
+        scalar_value: {
+            int32_t: 20
+        }
+    }
+}
+
diff --git a/graphics/composer/2.1/default/Hwc.cpp b/graphics/composer/2.1/default/Hwc.cpp
index 7fa5119..36c6e54 100644
--- a/graphics/composer/2.1/default/Hwc.cpp
+++ b/graphics/composer/2.1/default/Hwc.cpp
@@ -318,15 +318,15 @@
             presentDisplay_cb hidl_cb) override;
     Return<Error> setActiveConfig(Display display, Config config) override;
     Return<Error> setClientTarget(Display display,
-            const native_handle_t* target,
-            const native_handle_t* acquireFence,
+            const hidl_handle& target,
+            const hidl_handle& acquireFence,
             Dataspace dataspace, const hidl_vec<Rect>& damage) override;
     Return<Error> setColorMode(Display display, ColorMode mode) override;
     Return<Error> setColorTransform(Display display,
             const hidl_vec<float>& matrix, ColorTransform hint) override;
     Return<Error> setOutputBuffer(Display display,
-            const native_handle_t* buffer,
-            const native_handle_t* releaseFence) override;
+            const hidl_handle& buffer,
+            const hidl_handle& releaseFence) override;
     Return<Error> setPowerMode(Display display, PowerMode mode) override;
     Return<Error> setVsyncEnabled(Display display, Vsync enabled) override;
     Return<void> validateDisplay(Display display,
@@ -334,8 +334,8 @@
     Return<Error> setCursorPosition(Display display,
             Layer layer, int32_t x, int32_t y) override;
     Return<Error> setLayerBuffer(Display display,
-            Layer layer, const native_handle_t* buffer,
-            const native_handle_t* acquireFence) override;
+            Layer layer, const hidl_handle& buffer,
+            const hidl_handle& acquireFence) override;
     Return<Error> setLayerSurfaceDamage(Display display,
             Layer layer, const hidl_vec<Rect>& damage) override;
     Return<Error> setLayerBlendMode(Display display,
@@ -351,7 +351,7 @@
     Return<Error> setLayerPlaneAlpha(Display display,
             Layer layer, float alpha) override;
     Return<Error> setLayerSidebandStream(Display display,
-            Layer layer, const native_handle_t* stream) override;
+            Layer layer, const hidl_handle& stream) override;
     Return<Error> setLayerSourceCrop(Display display,
             Layer layer, const FRect& crop) override;
     Return<Error> setLayerTransform(Display display,
@@ -1027,17 +1027,18 @@
 }
 
 Return<Error> HwcHal::setClientTarget(Display display,
-        const native_handle_t* target,
-        const native_handle_t* acquireFence,
+        const hidl_handle& target,
+        const hidl_handle& acquireFence,
         Dataspace dataspace, const hidl_vec<Rect>& damage)
 {
-    if (!sHandleImporter.importBuffer(target)) {
+    const native_handle_t* targetHandle = target.getNativeHandle();
+    if (!sHandleImporter.importBuffer(targetHandle)) {
         return Error::NO_RESOURCES;
     }
 
     int32_t fence;
     if (!sHandleImporter.importFence(acquireFence, fence)) {
-        sHandleImporter.freeBuffer(target);
+        sHandleImporter.freeBuffer(targetHandle);
         return Error::NO_RESOURCES;
     }
 
@@ -1045,13 +1046,13 @@
         reinterpret_cast<const hwc_rect_t*>(&damage[0]) };
 
     int32_t error = mDispatch.setClientTarget(mDevice, display,
-            target, fence, static_cast<int32_t>(dataspace),
+            targetHandle, fence, static_cast<int32_t>(dataspace),
             damage_region);
     if (error == HWC2_ERROR_NONE) {
         std::lock_guard<std::mutex> lock(mDisplayMutex);
 
         auto dpy = mDisplays.find(display);
-        dpy->second.ClientTarget = target;
+        dpy->second.ClientTarget = targetHandle;
     } else {
         sHandleImporter.freeBuffer(target);
         sHandleImporter.closeFence(fence);
@@ -1076,28 +1077,29 @@
 }
 
 Return<Error> HwcHal::setOutputBuffer(Display display,
-        const native_handle_t* buffer,
-        const native_handle_t* releaseFence)
+        const hidl_handle& buffer,
+        const hidl_handle& releaseFence)
 {
-    if (!sHandleImporter.importBuffer(buffer)) {
+    const native_handle_t* bufferHandle = buffer.getNativeHandle();
+    if (!sHandleImporter.importBuffer(bufferHandle)) {
         return Error::NO_RESOURCES;
     }
 
     int32_t fence;
     if (!sHandleImporter.importFence(releaseFence, fence)) {
-        sHandleImporter.freeBuffer(buffer);
+        sHandleImporter.freeBuffer(bufferHandle);
         return Error::NO_RESOURCES;
     }
 
     int32_t error = mDispatch.setOutputBuffer(mDevice,
-            display, buffer, fence);
+            display, bufferHandle, fence);
     if (error == HWC2_ERROR_NONE) {
         std::lock_guard<std::mutex> lock(mDisplayMutex);
 
         auto dpy = mDisplays.find(display);
-        dpy->second.OutputBuffer = buffer;
+        dpy->second.OutputBuffer = bufferHandle;
     } else {
-        sHandleImporter.freeBuffer(buffer);
+        sHandleImporter.freeBuffer(bufferHandle);
     }
 
     // unlike in setClientTarget, fence is owned by us and is always closed
@@ -1142,28 +1144,29 @@
 }
 
 Return<Error> HwcHal::setLayerBuffer(Display display,
-        Layer layer, const native_handle_t* buffer,
-        const native_handle_t* acquireFence)
+        Layer layer, const hidl_handle& buffer,
+        const hidl_handle& acquireFence)
 {
-    if (!sHandleImporter.importBuffer(buffer)) {
+    const native_handle_t* bufferHandle = buffer.getNativeHandle();
+    if (!sHandleImporter.importBuffer(bufferHandle)) {
         return Error::NO_RESOURCES;
     }
 
     int32_t fence;
     if (!sHandleImporter.importFence(acquireFence, fence)) {
-        sHandleImporter.freeBuffer(buffer);
+        sHandleImporter.freeBuffer(bufferHandle);
         return Error::NO_RESOURCES;
     }
 
     int32_t error = mDispatch.setLayerBuffer(mDevice,
-            display, layer, buffer, fence);
+            display, layer, bufferHandle, fence);
     if (error == HWC2_ERROR_NONE) {
         std::lock_guard<std::mutex> lock(mDisplayMutex);
 
         auto dpy = mDisplays.find(display);
-        dpy->second.LayerBuffers[layer] = buffer;
+        dpy->second.LayerBuffers[layer] = bufferHandle;
     } else {
-        sHandleImporter.freeBuffer(buffer);
+        sHandleImporter.freeBuffer(bufferHandle);
         sHandleImporter.closeFence(fence);
     }
 
@@ -1230,21 +1233,22 @@
 }
 
 Return<Error> HwcHal::setLayerSidebandStream(Display display,
-        Layer layer, const native_handle_t* stream)
+        Layer layer, const hidl_handle& stream)
 {
-    if (!sHandleImporter.importBuffer(stream)) {
+    const native_handle_t* streamHandle = stream.getNativeHandle();
+    if (!sHandleImporter.importBuffer(streamHandle)) {
         return Error::NO_RESOURCES;
     }
 
     int32_t error = mDispatch.setLayerSidebandStream(mDevice,
-            display, layer, stream);
+            display, layer, streamHandle);
     if (error == HWC2_ERROR_NONE) {
         std::lock_guard<std::mutex> lock(mDisplayMutex);
 
         auto dpy = mDisplays.find(display);
-        dpy->second.LayerSidebandStreams[layer] = stream;
+        dpy->second.LayerSidebandStreams[layer] = streamHandle;
     } else {
-        sHandleImporter.freeBuffer(stream);
+        sHandleImporter.freeBuffer(streamHandle);
     }
 
     return static_cast<Error>(error);
diff --git a/nfc/1.0/INfc.hal b/nfc/1.0/INfc.hal
index f003b2c..1c952db 100644
--- a/nfc/1.0/INfc.hal
+++ b/nfc/1.0/INfc.hal
@@ -33,6 +33,8 @@
      * If open() returns any other value, the NCI stack will stop.
      *
      */
+    @entry
+    @callflow(next={"write", "coreInitialized", "prediscover", "powerCycle", "controlGranted"})
     open(INfcClientCallback clientCallback) generates (int32_t retval);
 
     /*
@@ -41,6 +43,8 @@
      * This method may queue writes and return immediately. The only
      * requirement is that the writes are executed in order.
      */
+    @callflow(next={"write", "prediscover", "coreInitialized", "close", "powerCycle",
+                    "controlGranted"})
     write(NfcData data) generates (int32_t retval);
 
     /*
@@ -53,6 +57,7 @@
      * If coreInitialized() returns any other value, the NCI stack will continue
      * immediately.
      */
+    @callflow(next={"write", "prediscover", "close"})
     coreInitialized(NfcData data) generates (int32_t retval);
 
     /*
@@ -66,11 +71,13 @@
      * If prediscover() returns any other value, the NCI stack will start
      * RF discovery immediately.
      */
+    @callflow(next={"write", "close", "coreInitialized", "powerCycle", "controlGranted"})
     prediscover() generates (int32_t retval);
 
     /*
      * Close the NFC controller. Should free all resources.
      */
+    @exit
     close() generates (int32_t retval);
 
     /*
@@ -79,11 +86,13 @@
      * Must only be called when there are no NCI commands pending.
      * NfcEvent.RELEASE_CONTROL will notify when HAL no longer needs exclusive control.
      */
+    @callflow(next={"write", "close", "prediscover", "coreInitialized", "powerCycle"})
     controlGranted() generates (int32_t retval);
 
      /*
      * Restart controller by power cyle;
      * NfcEvent.OPEN_CPLT will notify when operation is complete.
      */
+    @callflow(next={"write", "coreInitialized", "prediscover", "controlGranted", "close"})
     powerCycle() generates (int32_t retval);
 };
diff --git a/tests/bar/1.0/default/Bar.cpp b/tests/bar/1.0/default/Bar.cpp
index 2158cd8..c07e2fa 100644
--- a/tests/bar/1.0/default/Bar.cpp
+++ b/tests/bar/1.0/default/Bar.cpp
@@ -153,8 +153,8 @@
     return Void();
 }
 
-Return<void> Bar::expectNullHandle(const native_handle_t* h, const Abc& xyz, expectNullHandle_cb _hidl_cb) {
-    ALOGI("SERVER(Bar) h = %p, xyz.z = %p", h, static_cast<void*>(xyz.z));
+Return<void> Bar::expectNullHandle(const hidl_handle& h, const Abc& xyz, expectNullHandle_cb _hidl_cb) {
+    ALOGI("SERVER(Bar) h = %p, xyz.z = %p", h.getNativeHandle(), xyz.z.getNativeHandle());
     _hidl_cb(h == nullptr, xyz.z == nullptr);
     return Void();
 }
diff --git a/tests/bar/1.0/default/Bar.h b/tests/bar/1.0/default/Bar.h
index 4e22b61..29eedec 100644
--- a/tests/bar/1.0/default/Bar.h
+++ b/tests/bar/1.0/default/Bar.h
@@ -64,7 +64,7 @@
 
     // Methods from ::android::hardware::tests::bar::V1_0::IBar follow.
     Return<void> thisIsNew()  override;
-    Return<void> expectNullHandle(const native_handle_t* h, const Abc& xyz, expectNullHandle_cb _hidl_cb)  override;
+    Return<void> expectNullHandle(const hidl_handle& h, const Abc& xyz, expectNullHandle_cb _hidl_cb)  override;
 
 private:
     sp<IFoo> mFoo;
diff --git a/tests/foo/1.0/default/Foo.cpp b/tests/foo/1.0/default/Foo.cpp
index f7cc7c0..a1df3b2 100644
--- a/tests/foo/1.0/default/Foo.cpp
+++ b/tests/foo/1.0/default/Foo.cpp
@@ -309,7 +309,7 @@
 }
 
 Return<void> Foo::createHandles(uint32_t size, createHandles_cb _hidl_cb) {
-    hidl_vec<const native_handle_t*> handles;
+    hidl_vec<hidl_handle> handles;
     handles.resize(size);
     for(uint32_t i = 0; i < size; ++i) {
         createMyHandle([&](const MyHandle& h) {
diff --git a/wifi/1.0/default/wifi_legacy_hal.cpp b/wifi/1.0/default/wifi_legacy_hal.cpp
index 28b7f9a..15b6bfc 100644
--- a/wifi/1.0/default/wifi_legacy_hal.cpp
+++ b/wifi/1.0/default/wifi_legacy_hal.cpp
@@ -28,8 +28,14 @@
 namespace V1_0 {
 namespace implementation {
 namespace legacy_hal {
-// Constants used in the class.
+// Constants ported over from the legacy HAL calling code
+// (com_android_server_wifi_WifiNative.cpp). This will all be thrown
+// away when this shim layer is replaced by the real vendor
+// implementation.
 static constexpr uint32_t kMaxVersionStringLength = 256;
+static constexpr uint32_t kMaxCachedGscanResults = 64;
+static constexpr uint32_t kMaxGscanFrequenciesForBand = 64;
+static constexpr uint32_t kLinkLayerStatsDataMpduSizeThreshold = 128;
 
 // Legacy HAL functions accept "C" style function pointers, so use global
 // functions to pass to the legacy HAL function and store the corresponding
@@ -57,6 +63,40 @@
     on_firmware_memory_dump_internal_callback(buffer, buffer_size);
   }
 }
+
+// Callback to be invoked for Gscan events.
+std::function<void(wifi_request_id, wifi_scan_event)>
+    on_gscan_event_internal_callback;
+void onGscanEvent(wifi_request_id id, wifi_scan_event event) {
+  if (on_gscan_event_internal_callback) {
+    on_gscan_event_internal_callback(id, event);
+  }
+}
+
+// Callback to be invoked for Gscan full results.
+std::function<void(wifi_request_id, wifi_scan_result*, uint32_t)>
+    on_gscan_full_result_internal_callback;
+void onGscanFullResult(wifi_request_id id,
+                       wifi_scan_result* result,
+                       uint32_t buckets_scanned) {
+  if (on_gscan_full_result_internal_callback) {
+    on_gscan_full_result_internal_callback(id, result, buckets_scanned);
+  }
+}
+
+// Callback to be invoked for link layer stats results.
+std::function<void((wifi_request_id, wifi_iface_stat*, int, wifi_radio_stat*))>
+    on_link_layer_stats_result_internal_callback;
+void onLinkLayerStatsDataResult(wifi_request_id id,
+                                wifi_iface_stat* iface_stat,
+                                int num_radios,
+                                wifi_radio_stat* radio_stat) {
+  if (on_link_layer_stats_result_internal_callback) {
+    on_link_layer_stats_result_internal_callback(
+        id, iface_stat, num_radios, radio_stat);
+  }
+}
+
 // End of the free-standing "C" style callbacks.
 
 WifiLegacyHal::WifiLegacyHal()
@@ -206,6 +246,162 @@
       wlan_interface_handle_, program.data(), program.size());
 }
 
+std::pair<wifi_error, wifi_gscan_capabilities>
+WifiLegacyHal::getGscanCapabilities() {
+  wifi_gscan_capabilities caps;
+  wifi_error status = global_func_table_.wifi_get_gscan_capabilities(
+      wlan_interface_handle_, &caps);
+  return {status, caps};
+}
+
+wifi_error WifiLegacyHal::startGscan(
+    wifi_request_id id,
+    const wifi_scan_cmd_params& params,
+    const std::function<void(wifi_request_id)>& on_failure_user_callback,
+    const on_gscan_results_callback& on_results_user_callback,
+    const on_gscan_full_result_callback& on_full_result_user_callback) {
+  // If there is already an ongoing background scan, reject new scan requests.
+  if (on_gscan_event_internal_callback ||
+      on_gscan_full_result_internal_callback) {
+    return WIFI_ERROR_NOT_AVAILABLE;
+  }
+
+  // This callback will be used to either trigger |on_results_user_callback| or
+  // |on_failure_user_callback|.
+  on_gscan_event_internal_callback =
+      [on_failure_user_callback, on_results_user_callback, this](
+          wifi_request_id id, wifi_scan_event event) {
+        switch (event) {
+          case WIFI_SCAN_RESULTS_AVAILABLE:
+          case WIFI_SCAN_THRESHOLD_NUM_SCANS:
+          case WIFI_SCAN_THRESHOLD_PERCENT: {
+            wifi_error status;
+            std::vector<wifi_cached_scan_results> cached_scan_results;
+            std::tie(status, cached_scan_results) = getGscanCachedResults();
+            if (status == WIFI_SUCCESS) {
+              on_results_user_callback(id, cached_scan_results);
+              return;
+            }
+          }
+          // Fall through if failed. Failure to retrieve cached scan results
+          // should trigger a background scan failure.
+          case WIFI_SCAN_FAILED:
+            on_failure_user_callback(id);
+            on_gscan_event_internal_callback = nullptr;
+            on_gscan_full_result_internal_callback = nullptr;
+            return;
+        }
+        LOG(FATAL) << "Unexpected gscan event received: " << event;
+      };
+
+  on_gscan_full_result_internal_callback = [on_full_result_user_callback](
+      wifi_request_id id, wifi_scan_result* result, uint32_t buckets_scanned) {
+    if (result) {
+      on_full_result_user_callback(id, result, buckets_scanned);
+    }
+  };
+
+  wifi_scan_result_handler handler = {onGscanFullResult, onGscanEvent};
+  wifi_error status = global_func_table_.wifi_start_gscan(
+      id, wlan_interface_handle_, params, handler);
+  if (status != WIFI_SUCCESS) {
+    on_gscan_event_internal_callback = nullptr;
+    on_gscan_full_result_internal_callback = nullptr;
+  }
+  return status;
+}
+
+wifi_error WifiLegacyHal::stopGscan(wifi_request_id id) {
+  // If there is no an ongoing background scan, reject stop requests.
+  // TODO(b/32337212): This needs to be handled by the HIDL object because we
+  // need to return the NOT_STARTED error code.
+  if (!on_gscan_event_internal_callback &&
+      !on_gscan_full_result_internal_callback) {
+    return WIFI_ERROR_NOT_AVAILABLE;
+  }
+  wifi_error status =
+      global_func_table_.wifi_stop_gscan(id, wlan_interface_handle_);
+  // If the request Id is wrong, don't stop the ongoing background scan. Any
+  // other error should be treated as the end of background scan.
+  if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+    on_gscan_event_internal_callback = nullptr;
+    on_gscan_full_result_internal_callback = nullptr;
+  }
+  return status;
+}
+
+std::pair<wifi_error, std::vector<uint32_t>>
+WifiLegacyHal::getValidFrequenciesForGscan(wifi_band band) {
+  static_assert(sizeof(uint32_t) >= sizeof(wifi_channel),
+                "Wifi Channel cannot be represented in output");
+  std::vector<uint32_t> freqs;
+  freqs.resize(kMaxGscanFrequenciesForBand);
+  int32_t num_freqs = 0;
+  wifi_error status = global_func_table_.wifi_get_valid_channels(
+      wlan_interface_handle_,
+      band,
+      freqs.size(),
+      reinterpret_cast<wifi_channel*>(freqs.data()),
+      &num_freqs);
+  CHECK(num_freqs >= 0 &&
+        static_cast<uint32_t>(num_freqs) <= kMaxGscanFrequenciesForBand);
+  freqs.resize(num_freqs);
+  return {status, std::move(freqs)};
+}
+
+wifi_error WifiLegacyHal::enableLinkLayerStats(bool debug) {
+  wifi_link_layer_params params;
+  params.mpdu_size_threshold = kLinkLayerStatsDataMpduSizeThreshold;
+  params.aggressive_statistics_gathering = debug;
+  return global_func_table_.wifi_set_link_stats(wlan_interface_handle_, params);
+}
+
+wifi_error WifiLegacyHal::disableLinkLayerStats() {
+  // TODO: Do we care about these responses?
+  uint32_t clear_mask_rsp;
+  uint8_t stop_rsp;
+  return global_func_table_.wifi_clear_link_stats(
+      wlan_interface_handle_, 0xFFFFFFFF, &clear_mask_rsp, 1, &stop_rsp);
+}
+
+std::pair<wifi_error, LinkLayerStats> WifiLegacyHal::getLinkLayerStats() {
+  LinkLayerStats link_stats{};
+  LinkLayerStats* link_stats_ptr = &link_stats;
+
+  on_link_layer_stats_result_internal_callback = [&link_stats_ptr](
+      wifi_request_id /* id */,
+      wifi_iface_stat* iface_stats_ptr,
+      int num_radios,
+      wifi_radio_stat* radio_stats_ptr) {
+    if (iface_stats_ptr != nullptr) {
+      link_stats_ptr->iface = *iface_stats_ptr;
+      link_stats_ptr->iface.num_peers = 0;
+    } else {
+      LOG(ERROR) << "Invalid iface stats in link layer stats";
+    }
+    if (num_radios == 1 && radio_stats_ptr != nullptr) {
+      link_stats_ptr->radio = *radio_stats_ptr;
+      // Copy over the tx level array to the separate vector.
+      if (radio_stats_ptr->num_tx_levels > 0 &&
+          radio_stats_ptr->tx_time_per_levels != nullptr) {
+        link_stats_ptr->radio_tx_time_per_levels.assign(
+            radio_stats_ptr->tx_time_per_levels,
+            radio_stats_ptr->tx_time_per_levels +
+                radio_stats_ptr->num_tx_levels);
+      }
+      link_stats_ptr->radio.num_tx_levels = 0;
+      link_stats_ptr->radio.tx_time_per_levels = nullptr;
+    } else {
+      LOG(ERROR) << "Invalid radio stats in link layer stats";
+    }
+  };
+
+  wifi_error status = global_func_table_.wifi_get_link_stats(
+      0, wlan_interface_handle_, {onLinkLayerStatsDataResult});
+  on_link_layer_stats_result_internal_callback = nullptr;
+  return {status, link_stats};
+}
+
 wifi_error WifiLegacyHal::retrieveWlanInterfaceHandle() {
   const std::string& ifname_to_find = getStaIfaceName();
   wifi_interface_handle* iface_handles = nullptr;
@@ -245,12 +441,44 @@
   if_tool.SetWifiUpState(false);
 }
 
+std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
+WifiLegacyHal::getGscanCachedResults() {
+  std::vector<wifi_cached_scan_results> cached_scan_results;
+  cached_scan_results.resize(kMaxCachedGscanResults);
+  int32_t num_results = 0;
+  wifi_error status = global_func_table_.wifi_get_cached_gscan_results(
+      wlan_interface_handle_,
+      true /* always flush */,
+      cached_scan_results.size(),
+      cached_scan_results.data(),
+      &num_results);
+  CHECK(num_results >= 0 &&
+        static_cast<uint32_t>(num_results) <= kMaxCachedGscanResults);
+  cached_scan_results.resize(num_results);
+  // Check for invalid IE lengths in these cached scan results and correct it.
+  for (auto& cached_scan_result : cached_scan_results) {
+    int num_scan_results = cached_scan_result.num_results;
+    for (int i = 0; i < num_scan_results; i++) {
+      auto& scan_result = cached_scan_result.results[i];
+      if (scan_result.ie_length > 0) {
+        LOG(ERROR) << "Cached scan result has non-zero IE length "
+                   << scan_result.ie_length;
+        scan_result.ie_length = 0;
+      }
+    }
+  }
+  return {status, std::move(cached_scan_results)};
+}
+
 void WifiLegacyHal::invalidate() {
   global_handle_ = nullptr;
   wlan_interface_handle_ = nullptr;
   on_stop_complete_internal_callback = nullptr;
   on_driver_memory_dump_internal_callback = nullptr;
   on_firmware_memory_dump_internal_callback = nullptr;
+  on_gscan_event_internal_callback = nullptr;
+  on_gscan_full_result_internal_callback = nullptr;
+  on_link_layer_stats_result_internal_callback = nullptr;
 }
 
 }  // namespace legacy_hal
diff --git a/wifi/1.0/default/wifi_legacy_hal.h b/wifi/1.0/default/wifi_legacy_hal.h
index 8bd146a..df1c3d6 100644
--- a/wifi/1.0/default/wifi_legacy_hal.h
+++ b/wifi/1.0/default/wifi_legacy_hal.h
@@ -39,6 +39,31 @@
   uint32_t max_len;
 };
 
+// WARNING: We don't care about the variable sized members of either
+// |wifi_iface_stat|, |wifi_radio_stat| structures. So, using the pragma
+// to escape the compiler warnings regarding this.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
+// The |wifi_radio_stat.tx_time_per_levels| stats is provided as a pointer in
+// |wifi_radio_stat| structure in the legacy HAL API. Separate that out
+// into a separate return element to avoid passing pointers around.
+struct LinkLayerStats {
+  wifi_iface_stat iface;
+  wifi_radio_stat radio;
+  std::vector<uint32_t> radio_tx_time_per_levels;
+};
+#pragma GCC diagnostic pop
+
+// Full scan results contain IE info and are hence passed by reference, to
+// preserve the variable length array member |ie_data|. Callee must not retain
+// the pointer.
+using on_gscan_full_result_callback =
+    std::function<void(wifi_request_id, const wifi_scan_result*, uint32_t)>;
+// These scan results don't contain any IE info, so no need to pass by
+// reference.
+using on_gscan_results_callback = std::function<void(
+    wifi_request_id, const std::vector<wifi_cached_scan_results>&)>;
+
 /**
  * Class that encapsulates all legacy HAL interactions.
  * This class manages the lifetime of the event loop thread used by legacy HAL.
@@ -65,12 +90,41 @@
   // APF functions.
   std::pair<wifi_error, PacketFilterCapabilities> getPacketFilterCapabilities();
   wifi_error setPacketFilter(const std::vector<uint8_t>& program);
+  // Gscan functions.
+  std::pair<wifi_error, wifi_gscan_capabilities> getGscanCapabilities();
+  // These API's provides a simplified interface over the legacy Gscan API's:
+  // a) All scan events from the legacy HAL API other than the
+  //    |WIFI_SCAN_FAILED| are treated as notification of results.
+  //    This method then retrieves the cached scan results from the legacy
+  //    HAL API and triggers the externally provided |on_results_user_callback|
+  //    on success.
+  // b) |WIFI_SCAN_FAILED| scan event or failure to retrieve cached scan results
+  //    triggers the externally provided |on_failure_user_callback|.
+  // c) Full scan result event triggers the externally provided
+  //    |on_full_result_user_callback|.
+  wifi_error startGscan(
+      wifi_request_id id,
+      const wifi_scan_cmd_params& params,
+      const std::function<void(wifi_request_id)>& on_failure_callback,
+      const on_gscan_results_callback& on_results_callback,
+      const on_gscan_full_result_callback& on_full_result_callback);
+  wifi_error stopGscan(wifi_request_id id);
+  std::pair<wifi_error, std::vector<uint32_t>> getValidFrequenciesForGscan(
+      wifi_band band);
+  // Link layer stats functions.
+  wifi_error enableLinkLayerStats(bool debug);
+  wifi_error disableLinkLayerStats();
+  std::pair<wifi_error, LinkLayerStats> getLinkLayerStats();
 
  private:
   // Retrieve the interface handle to be used for the "wlan" interface.
   wifi_error retrieveWlanInterfaceHandle();
   // Run the legacy HAL event loop thread.
   void runEventLoop();
+  // Retrieve the cached gscan results to pass the results back to the external
+  // callbacks.
+  std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
+  getGscanCachedResults();
   void invalidate();
 
   // Event loop thread used by legacy HAL.