Merge "Add new secure stop methods"
diff --git a/automotive/audiocontrol/1.0/default/android.hardware.automotive.audiocontrol@1.0-service.rc b/automotive/audiocontrol/1.0/default/android.hardware.automotive.audiocontrol@1.0-service.rc
index 79edad6..c02db08 100644
--- a/automotive/audiocontrol/1.0/default/android.hardware.automotive.audiocontrol@1.0-service.rc
+++ b/automotive/audiocontrol/1.0/default/android.hardware.automotive.audiocontrol@1.0-service.rc
@@ -1,4 +1,4 @@
-service vendor.evs-hal-mock /vendor/bin/hw/android.hardware.automotive.audiocontrol@1.0-service
+service vendor.audiocontrol-hal-1.0 /vendor/bin/hw/android.hardware.automotive.audiocontrol@1.0-service
     class hal
     user audioserver
     group system
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
index 3f98a94..40dd56e 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
@@ -47,6 +47,7 @@
 
     dest->prop = src.prop;
     dest->areaId = src.areaId;
+    dest->status = src.status;
     dest->timestamp = src.timestamp;
     copyVehicleRawValue(&dest->value, src.value);
 
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
index 34a6380..5b6816e 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
@@ -114,6 +114,7 @@
 void shallowCopy(VehiclePropValue* dest, const VehiclePropValue& src) {
     dest->prop = src.prop;
     dest->areaId = src.areaId;
+    dest->status = src.status;
     dest->timestamp = src.timestamp;
     shallowCopyHidlVec(&dest->value.int32Values, src.value.int32Values);
     shallowCopyHidlVec(&dest->value.int64Values, src.value.int64Values);
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index 16d2b0b..5118b18 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -363,6 +363,7 @@
         updatedPropValue->prop = propId;
         updatedPropValue->areaId = 0;  // Add area support if necessary.
         updatedPropValue->timestamp = elapsedRealtimeNano();
+        updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
         mPropStore->writeValue(*updatedPropValue);
         auto changeMode = mPropStore->getConfigOrDie(propId)->changeMode;
         if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
index fca8e9e..bf7be09 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
@@ -138,6 +138,7 @@
     VehiclePropValue val = {
         .prop = protoVal.prop(),
         .areaId = protoVal.area_id(),
+        .status = (VehiclePropertyStatus)protoVal.status(),
         .timestamp = elapsedRealtimeNano(),
     };
 
@@ -288,6 +289,7 @@
     protoVal->set_prop(val->prop);
     protoVal->set_value_type(toInt(getPropType(val->prop)));
     protoVal->set_timestamp(val->timestamp);
+    protoVal->set_status((emulator::VehiclePropStatus)(val->status));
     protoVal->set_area_id(val->areaId);
 
     // Copy value data if it is set.
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
index 86433f5..2ef64fb 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
@@ -46,6 +46,12 @@
     ERROR_INVALID_OPERATION             = 8;
 }
 
+enum VehiclePropStatus {
+    AVAILABLE                           = 0;
+    UNAVAILABLE                         = 1;
+    ERROR                               = 2;
+}
+
 message VehicleAreaConfig {
     required int32  area_id             = 1;
     optional sint32 min_int32_value     = 2;
@@ -61,7 +67,7 @@
     optional int32             access              = 2;
     optional int32             change_mode         = 3;
     optional int32             value_type          = 4;
-    optional int32             supported_areas     = 5;
+    optional int32             supported_areas     = 5;     // Deprecated - DO NOT USE
     repeated VehicleAreaConfig area_configs        = 6;
     optional int32             config_flags        = 7;
     repeated int32             config_array        = 8;
@@ -75,6 +81,7 @@
     required int32  prop                = 1;
     optional int32  value_type          = 2;
     optional int64  timestamp           = 3;    // required for valid data from HAL, skipped for set
+    optional VehiclePropStatus  status  = 10;   // required for valid data from HAL, skipped for set
 
     // values
     optional int32  area_id             = 4;
diff --git a/camera/common/1.0/default/Android.bp b/camera/common/1.0/default/Android.bp
index 6209cb8..21f81f5 100644
--- a/camera/common/1.0/default/Android.bp
+++ b/camera/common/1.0/default/Android.bp
@@ -7,7 +7,9 @@
         "CameraMetadata.cpp",
         "CameraParameters.cpp",
         "VendorTagDescriptor.cpp",
-        "HandleImporter.cpp"],
+        "HandleImporter.cpp",
+        "Exif.cpp"
+    ],
     cflags: [
         "-Werror",
         "-Wextra",
@@ -17,7 +19,9 @@
         "liblog",
         "libhardware",
         "libcamera_metadata",
-        "android.hardware.graphics.mapper@2.0"],
+        "android.hardware.graphics.mapper@2.0",
+        "libexif",
+    ],
     include_dirs: ["system/media/private/camera/include"],
     export_include_dirs : ["include"]
 }
diff --git a/camera/common/1.0/default/Exif.cpp b/camera/common/1.0/default/Exif.cpp
new file mode 100644
index 0000000..3e894f9
--- /dev/null
+++ b/camera/common/1.0/default/Exif.cpp
@@ -0,0 +1,1115 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CamComm1.0-Exif"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+
+#include <inttypes.h>
+#include <math.h>
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include "Exif.h"
+
+extern "C" {
+#include <libexif/exif-data.h>
+}
+
+namespace std {
+
+template <>
+struct default_delete<ExifEntry> {
+    inline void operator()(ExifEntry* entry) const { exif_entry_unref(entry); }
+};
+
+}  // namespace std
+
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+
+class ExifUtilsImpl : public ExifUtils {
+  public:
+    ExifUtilsImpl();
+
+    virtual ~ExifUtilsImpl();
+
+    // Initialize() can be called multiple times. The setting of Exif tags will be
+    // cleared.
+    virtual bool initialize();
+
+    // set all known fields from a metadata structure
+    virtual bool setFromMetadata(const CameraMetadata& metadata,
+                                 const size_t imageWidth,
+                                 const size_t imageHeight);
+
+    // sets the len aperture.
+    // Returns false if memory allocation fails.
+    virtual bool setAperture(uint32_t numerator, uint32_t denominator);
+
+    // sets the value of brightness.
+    // Returns false if memory allocation fails.
+    virtual bool setBrightness(int32_t numerator, int32_t denominator);
+
+    // sets the color space.
+    // Returns false if memory allocation fails.
+    virtual bool setColorSpace(uint16_t color_space);
+
+    // sets the information to compressed data.
+    // Returns false if memory allocation fails.
+    virtual bool setComponentsConfiguration(const std::string& components_configuration);
+
+    // sets the compression scheme used for the image data.
+    // Returns false if memory allocation fails.
+    virtual bool setCompression(uint16_t compression);
+
+    // sets image contrast.
+    // Returns false if memory allocation fails.
+    virtual bool setContrast(uint16_t contrast);
+
+    // sets the date and time of image last modified. It takes local time. The
+    // name of the tag is DateTime in IFD0.
+    // Returns false if memory allocation fails.
+    virtual bool setDateTime(const struct tm& t);
+
+    // sets the image description.
+    // Returns false if memory allocation fails.
+    virtual bool setDescription(const std::string& description);
+
+    // sets the digital zoom ratio. If the numerator is 0, it means digital zoom
+    // was not used.
+    // Returns false if memory allocation fails.
+    virtual bool setDigitalZoomRatio(uint32_t numerator, uint32_t denominator);
+
+    // sets the exposure bias.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureBias(int32_t numerator, int32_t denominator);
+
+    // sets the exposure mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureMode(uint16_t exposure_mode);
+
+    // sets the program used by the camera to set exposure when the picture is
+    // taken.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureProgram(uint16_t exposure_program);
+
+    // sets the exposure time, given in seconds.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureTime(uint32_t numerator, uint32_t denominator);
+
+    // sets the status of flash.
+    // Returns false if memory allocation fails.
+    virtual bool setFlash(uint16_t flash);
+
+    // sets the F number.
+    // Returns false if memory allocation fails.
+    virtual bool setFNumber(uint32_t numerator, uint32_t denominator);
+
+    // sets the focal length of lens used to take the image in millimeters.
+    // Returns false if memory allocation fails.
+    virtual bool setFocalLength(uint32_t numerator, uint32_t denominator);
+
+    // sets the degree of overall image gain adjustment.
+    // Returns false if memory allocation fails.
+    virtual bool setGainControl(uint16_t gain_control);
+
+    // sets the altitude in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsAltitude(double altitude);
+
+    // sets the latitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLatitude(double latitude);
+
+    // sets the longitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLongitude(double longitude);
+
+    // sets GPS processing method.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsProcessingMethod(const std::string& method);
+
+    // sets GPS date stamp and time stamp (atomic clock). It takes UTC time.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsTimestamp(const struct tm& t);
+
+    // sets the length (number of rows) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageHeight(uint32_t length);
+
+    // sets the width (number of columes) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageWidth(uint32_t width);
+
+    // sets the ISO speed.
+    // Returns false if memory allocation fails.
+    virtual bool setIsoSpeedRating(uint16_t iso_speed_ratings);
+
+    // sets the kind of light source.
+    // Returns false if memory allocation fails.
+    virtual bool setLightSource(uint16_t light_source);
+
+    // sets the smallest F number of the lens.
+    // Returns false if memory allocation fails.
+    virtual bool setMaxAperture(uint32_t numerator, uint32_t denominator);
+
+    // sets the metering mode.
+    // Returns false if memory allocation fails.
+    virtual bool setMeteringMode(uint16_t metering_mode);
+
+    // sets image orientation.
+    // Returns false if memory allocation fails.
+    virtual bool setOrientation(uint16_t orientation);
+
+    // sets the unit for measuring XResolution and YResolution.
+    // Returns false if memory allocation fails.
+    virtual bool setResolutionUnit(uint16_t resolution_unit);
+
+    // sets image saturation.
+    // Returns false if memory allocation fails.
+    virtual bool setSaturation(uint16_t saturation);
+
+    // sets the type of scene that was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setSceneCaptureType(uint16_t type);
+
+    // sets image sharpness.
+    // Returns false if memory allocation fails.
+    virtual bool setSharpness(uint16_t sharpness);
+
+    // sets the shutter speed.
+    // Returns false if memory allocation fails.
+    virtual bool setShutterSpeed(int32_t numerator, int32_t denominator);
+
+    // sets the distance to the subject, given in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setSubjectDistance(uint32_t numerator, uint32_t denominator);
+
+    // sets the fractions of seconds for the <DateTime> tag.
+    // Returns false if memory allocation fails.
+    virtual bool setSubsecTime(const std::string& subsec_time);
+
+    // sets the white balance mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setWhiteBalance(uint16_t white_balance);
+
+    // sets the number of pixels per resolution unit in the image width.
+    // Returns false if memory allocation fails.
+    virtual bool setXResolution(uint32_t numerator, uint32_t denominator);
+
+    // sets the position of chrominance components in relation to the luminance
+    // component.
+    // Returns false if memory allocation fails.
+    virtual bool setYCbCrPositioning(uint16_t ycbcr_positioning);
+
+    // sets the number of pixels per resolution unit in the image length.
+    // Returns false if memory allocation fails.
+    virtual bool setYResolution(uint32_t numerator, uint32_t denominator);
+
+    // sets the manufacturer of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setMake(const std::string& make);
+
+    // sets the model number of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setModel(const std::string& model);
+
+    // Generates APP1 segment.
+    // Returns false if generating APP1 segment fails.
+    virtual bool generateApp1(const void* thumbnail_buffer, uint32_t size);
+
+    // Gets buffer of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual const uint8_t* getApp1Buffer();
+
+    // Gets length of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual unsigned int getApp1Length();
+
+  protected:
+    // sets the version of this standard supported.
+    // Returns false if memory allocation fails.
+    virtual bool setExifVersion(const std::string& exif_version);
+
+
+    // Resets the pointers and memories.
+    virtual void reset();
+
+    // Adds a variable length tag to |exif_data_|. It will remove the original one
+    // if the tag exists.
+    // Returns the entry of the tag. The reference count of returned ExifEntry is
+    // two.
+    virtual std::unique_ptr<ExifEntry> addVariableLengthEntry(ExifIfd ifd,
+                                                              ExifTag tag,
+                                                              ExifFormat format,
+                                                              uint64_t components,
+                                                              unsigned int size);
+
+    // Adds a entry of |tag| in |exif_data_|. It won't remove the original one if
+    // the tag exists.
+    // Returns the entry of the tag. It adds one reference count to returned
+    // ExifEntry.
+    virtual std::unique_ptr<ExifEntry> addEntry(ExifIfd ifd, ExifTag tag);
+
+    // Helpe functions to add exif data with different types.
+    virtual bool setShort(ExifIfd ifd,
+                          ExifTag tag,
+                          uint16_t value,
+                          const std::string& msg);
+
+    virtual bool setLong(ExifIfd ifd,
+                         ExifTag tag,
+                         uint32_t value,
+                         const std::string& msg);
+
+    virtual bool setRational(ExifIfd ifd,
+                             ExifTag tag,
+                             uint32_t numerator,
+                             uint32_t denominator,
+                             const std::string& msg);
+
+    virtual bool setSRational(ExifIfd ifd,
+                              ExifTag tag,
+                              int32_t numerator,
+                              int32_t denominator,
+                              const std::string& msg);
+
+    virtual bool setString(ExifIfd ifd,
+                           ExifTag tag,
+                           ExifFormat format,
+                           const std::string& buffer,
+                           const std::string& msg);
+
+    // Destroys the buffer of APP1 segment if exists.
+    virtual void destroyApp1();
+
+    // The Exif data (APP1). Owned by this class.
+    ExifData* exif_data_;
+    // The raw data of APP1 segment. It's allocated by ExifMem in |exif_data_| but
+    // owned by this class.
+    uint8_t* app1_buffer_;
+    // The length of |app1_buffer_|.
+    unsigned int app1_length_;
+
+};
+
+#define SET_SHORT(ifd, tag, value)                      \
+    do {                                                \
+        if (setShort(ifd, tag, value, #tag) == false)   \
+            return false;                               \
+    } while (0);
+
+#define SET_LONG(ifd, tag, value)                       \
+    do {                                                \
+        if (setLong(ifd, tag, value, #tag) == false)    \
+            return false;                               \
+    } while (0);
+
+#define SET_RATIONAL(ifd, tag, numerator, denominator)                      \
+    do {                                                                    \
+        if (setRational(ifd, tag, numerator, denominator, #tag) == false)   \
+            return false;                                                   \
+    } while (0);
+
+#define SET_SRATIONAL(ifd, tag, numerator, denominator)                       \
+    do {                                                                      \
+        if (setSRational(ifd, tag, numerator, denominator, #tag) == false)    \
+            return false;                                                     \
+    } while (0);
+
+#define SET_STRING(ifd, tag, format, buffer)                                  \
+    do {                                                                      \
+        if (setString(ifd, tag, format, buffer, #tag) == false)               \
+            return false;                                                     \
+    } while (0);
+
+// This comes from the Exif Version 2.2 standard table 6.
+const char gExifAsciiPrefix[] = {0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0};
+
+static void setLatitudeOrLongitudeData(unsigned char* data, double num) {
+    // Take the integer part of |num|.
+    ExifLong degrees = static_cast<ExifLong>(num);
+    ExifLong minutes = static_cast<ExifLong>(60 * (num - degrees));
+    ExifLong microseconds =
+            static_cast<ExifLong>(3600000000u * (num - degrees - minutes / 60.0));
+    exif_set_rational(data, EXIF_BYTE_ORDER_INTEL, {degrees, 1});
+    exif_set_rational(data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
+                                        {minutes, 1});
+    exif_set_rational(data + 2 * sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
+                                        {microseconds, 1000000});
+}
+
+ExifUtils *ExifUtils::create() {
+    return new ExifUtilsImpl();
+}
+
+ExifUtils::~ExifUtils() {
+}
+
+ExifUtilsImpl::ExifUtilsImpl()
+        : exif_data_(nullptr), app1_buffer_(nullptr), app1_length_(0) {}
+
+ExifUtilsImpl::~ExifUtilsImpl() {
+    reset();
+}
+
+
+bool ExifUtilsImpl::initialize() {
+    reset();
+    exif_data_ = exif_data_new();
+    if (exif_data_ == nullptr) {
+        ALOGE("%s: allocate memory for exif_data_ failed", __FUNCTION__);
+        return false;
+    }
+    // set the image options.
+    exif_data_set_option(exif_data_, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
+    exif_data_set_data_type(exif_data_, EXIF_DATA_TYPE_COMPRESSED);
+    exif_data_set_byte_order(exif_data_, EXIF_BYTE_ORDER_INTEL);
+
+    // set exif version to 2.2.
+    if (!setExifVersion("0220")) {
+        return false;
+    }
+
+    return true;
+}
+
+bool ExifUtilsImpl::setAperture(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_APERTURE_VALUE, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setBrightness(int32_t numerator, int32_t denominator) {
+    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_BRIGHTNESS_VALUE, numerator,
+                                denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setColorSpace(uint16_t color_space) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_COLOR_SPACE, color_space);
+    return true;
+}
+
+bool ExifUtilsImpl::setComponentsConfiguration(
+        const std::string& components_configuration) {
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_COMPONENTS_CONFIGURATION,
+                          EXIF_FORMAT_UNDEFINED, components_configuration);
+    return true;
+}
+
+bool ExifUtilsImpl::setCompression(uint16_t compression) {
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_COMPRESSION, compression);
+    return true;
+}
+
+bool ExifUtilsImpl::setContrast(uint16_t contrast) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_CONTRAST, contrast);
+    return true;
+}
+
+bool ExifUtilsImpl::setDateTime(const struct tm& t) {
+    // The length is 20 bytes including NULL for termination in Exif standard.
+    char str[20];
+    int result = snprintf(str, sizeof(str), "%04i:%02i:%02i %02i:%02i:%02i",
+                                                t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour,
+                                                t.tm_min, t.tm_sec);
+    if (result != sizeof(str) - 1) {
+        ALOGW("%s: Input time is invalid", __FUNCTION__);
+        return false;
+    }
+    std::string buffer(str);
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_DATE_TIME, EXIF_FORMAT_ASCII, buffer);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, EXIF_FORMAT_ASCII,
+                          buffer);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, EXIF_FORMAT_ASCII,
+                          buffer);
+    return true;
+}
+
+bool ExifUtilsImpl::setDescription(const std::string& description) {
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_IMAGE_DESCRIPTION, EXIF_FORMAT_ASCII,
+                          description);
+    return true;
+}
+
+bool ExifUtilsImpl::setDigitalZoomRatio(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_DIGITAL_ZOOM_RATIO, numerator,
+                              denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureBias(int32_t numerator, int32_t denominator) {
+    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_BIAS_VALUE, numerator,
+                                denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureMode(uint16_t exposure_mode) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_MODE, exposure_mode);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureProgram(uint16_t exposure_program) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_PROGRAM, exposure_program);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureTime(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setFlash(uint16_t flash) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_FLASH, flash);
+    return true;
+}
+
+bool ExifUtilsImpl::setFNumber(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_FNUMBER, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setFocalLength(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setGainControl(uint16_t gain_control) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_GAIN_CONTROL, gain_control);
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsAltitude(double altitude) {
+    ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF);
+    std::unique_ptr<ExifEntry> refEntry =
+            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_BYTE, 1, 1);
+    if (!refEntry) {
+        ALOGE("%s: Adding GPSAltitudeRef exif entry failed", __FUNCTION__);
+        return false;
+    }
+    if (altitude >= 0) {
+        *refEntry->data = 0;
+    } else {
+        *refEntry->data = 1;
+        altitude *= -1;
+    }
+
+    ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE);
+    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
+            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 1, sizeof(ExifRational));
+    if (!entry) {
+        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
+        ALOGE("%s: Adding GPSAltitude exif entry failed", __FUNCTION__);
+        return false;
+    }
+    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
+                                        {static_cast<ExifLong>(altitude * 1000), 1000});
+
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsLatitude(double latitude) {
+    const ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE_REF);
+    std::unique_ptr<ExifEntry> refEntry =
+            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_ASCII, 2, 2);
+    if (!refEntry) {
+        ALOGE("%s: Adding GPSLatitudeRef exif entry failed", __FUNCTION__);
+        return false;
+    }
+    if (latitude >= 0) {
+        memcpy(refEntry->data, "N", sizeof("N"));
+    } else {
+        memcpy(refEntry->data, "S", sizeof("S"));
+        latitude *= -1;
+    }
+
+    const ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE);
+    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
+            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 3, 3 * sizeof(ExifRational));
+    if (!entry) {
+        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
+        ALOGE("%s: Adding GPSLatitude exif entry failed", __FUNCTION__);
+        return false;
+    }
+    setLatitudeOrLongitudeData(entry->data, latitude);
+
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsLongitude(double longitude) {
+    ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE_REF);
+    std::unique_ptr<ExifEntry> refEntry =
+            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_ASCII, 2, 2);
+    if (!refEntry) {
+        ALOGE("%s: Adding GPSLongitudeRef exif entry failed", __FUNCTION__);
+        return false;
+    }
+    if (longitude >= 0) {
+        memcpy(refEntry->data, "E", sizeof("E"));
+    } else {
+        memcpy(refEntry->data, "W", sizeof("W"));
+        longitude *= -1;
+    }
+
+    ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE);
+    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
+            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 3, 3 * sizeof(ExifRational));
+    if (!entry) {
+        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
+        ALOGE("%s: Adding GPSLongitude exif entry failed", __FUNCTION__);
+        return false;
+    }
+    setLatitudeOrLongitudeData(entry->data, longitude);
+
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsProcessingMethod(const std::string& method) {
+    std::string buffer =
+            std::string(gExifAsciiPrefix, sizeof(gExifAsciiPrefix)) + method;
+    SET_STRING(EXIF_IFD_GPS, static_cast<ExifTag>(EXIF_TAG_GPS_PROCESSING_METHOD),
+                          EXIF_FORMAT_UNDEFINED, buffer);
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsTimestamp(const struct tm& t) {
+    const ExifTag dateTag = static_cast<ExifTag>(EXIF_TAG_GPS_DATE_STAMP);
+    const size_t kGpsDateStampSize = 11;
+    std::unique_ptr<ExifEntry> entry =
+            addVariableLengthEntry(EXIF_IFD_GPS, dateTag, EXIF_FORMAT_ASCII,
+                                                          kGpsDateStampSize, kGpsDateStampSize);
+    if (!entry) {
+        ALOGE("%s: Adding GPSDateStamp exif entry failed", __FUNCTION__);
+        return false;
+    }
+    int result =
+            snprintf(reinterpret_cast<char*>(entry->data), kGpsDateStampSize,
+                              "%04i:%02i:%02i", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday);
+    if (result != kGpsDateStampSize - 1) {
+        ALOGW("%s: Input time is invalid", __FUNCTION__);
+        return false;
+    }
+
+    const ExifTag timeTag = static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP);
+    entry = addVariableLengthEntry(EXIF_IFD_GPS, timeTag, EXIF_FORMAT_RATIONAL, 3,
+                                                                  3 * sizeof(ExifRational));
+    if (!entry) {
+        ALOGE("%s: Adding GPSTimeStamp exif entry failed", __FUNCTION__);
+        return false;
+    }
+    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
+                                        {static_cast<ExifLong>(t.tm_hour), 1});
+    exif_set_rational(entry->data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
+                                        {static_cast<ExifLong>(t.tm_min), 1});
+    exif_set_rational(entry->data + 2 * sizeof(ExifRational),
+                                        EXIF_BYTE_ORDER_INTEL,
+                                        {static_cast<ExifLong>(t.tm_sec), 1});
+
+    return true;
+}
+
+bool ExifUtilsImpl::setImageHeight(uint32_t length) {
+    SET_LONG(EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH, length);
+    SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_Y_DIMENSION, length);
+    return true;
+}
+
+bool ExifUtilsImpl::setImageWidth(uint32_t width) {
+    SET_LONG(EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH, width);
+    SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_X_DIMENSION, width);
+    return true;
+}
+
+bool ExifUtilsImpl::setIsoSpeedRating(uint16_t iso_speed_ratings) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, iso_speed_ratings);
+    return true;
+}
+
+bool ExifUtilsImpl::setLightSource(uint16_t light_source) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_LIGHT_SOURCE, light_source);
+    return true;
+}
+
+bool ExifUtilsImpl::setMaxAperture(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_MAX_APERTURE_VALUE, numerator,
+                              denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setMeteringMode(uint16_t metering_mode) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_METERING_MODE, metering_mode);
+    return true;
+}
+
+bool ExifUtilsImpl::setOrientation(uint16_t orientation) {
+    /*
+     * Orientation value:
+     *  1      2      3      4      5          6          7          8
+     *
+     *  888888 888888     88 88     8888888888 88                 88 8888888888
+     *  88         88     88 88     88  88     88  88         88  88     88  88
+     *  8888     8888   8888 8888   88         8888888888 8888888888         88
+     *  88         88     88 88
+     *  88         88 888888 888888
+     */
+    int value = 1;
+    switch (orientation) {
+        case 90:
+            value = 6;
+            break;
+        case 180:
+            value = 3;
+            break;
+        case 270:
+            value = 8;
+            break;
+        default:
+            break;
+    }
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_ORIENTATION, value);
+    return true;
+}
+
+bool ExifUtilsImpl::setResolutionUnit(uint16_t resolution_unit) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_RESOLUTION_UNIT, resolution_unit);
+    return true;
+}
+
+bool ExifUtilsImpl::setSaturation(uint16_t saturation) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SATURATION, saturation);
+    return true;
+}
+
+bool ExifUtilsImpl::setSceneCaptureType(uint16_t type) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SCENE_CAPTURE_TYPE, type);
+    return true;
+}
+
+bool ExifUtilsImpl::setSharpness(uint16_t sharpness) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SHARPNESS, sharpness);
+    return true;
+}
+
+bool ExifUtilsImpl::setShutterSpeed(int32_t numerator, int32_t denominator) {
+    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_SHUTTER_SPEED_VALUE, numerator,
+                                denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setSubjectDistance(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_SUBJECT_DISTANCE, numerator,
+                              denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setSubsecTime(const std::string& subsec_time) {
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME, EXIF_FORMAT_ASCII,
+                          subsec_time);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_ORIGINAL, EXIF_FORMAT_ASCII,
+                          subsec_time);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_DIGITIZED, EXIF_FORMAT_ASCII,
+                          subsec_time);
+    return true;
+}
+
+bool ExifUtilsImpl::setWhiteBalance(uint16_t white_balance) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_WHITE_BALANCE, white_balance);
+    return true;
+}
+
+bool ExifUtilsImpl::setXResolution(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_X_RESOLUTION, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setYCbCrPositioning(uint16_t ycbcr_positioning) {
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_YCBCR_POSITIONING, ycbcr_positioning);
+    return true;
+}
+
+bool ExifUtilsImpl::setYResolution(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_Y_RESOLUTION, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::generateApp1(const void* thumbnail_buffer, uint32_t size) {
+    destroyApp1();
+    exif_data_->data = const_cast<uint8_t*>(static_cast<const uint8_t*>(thumbnail_buffer));
+    exif_data_->size = size;
+    // Save the result into |app1_buffer_|.
+    exif_data_save_data(exif_data_, &app1_buffer_, &app1_length_);
+    if (!app1_length_) {
+        ALOGE("%s: Allocate memory for app1_buffer_ failed", __FUNCTION__);
+        return false;
+    }
+    /*
+     * The JPEG segment size is 16 bits in spec. The size of APP1 segment should
+     * be smaller than 65533 because there are two bytes for segment size field.
+     */
+    if (app1_length_ > 65533) {
+        destroyApp1();
+        ALOGE("%s: The size of APP1 segment is too large", __FUNCTION__);
+        return false;
+    }
+    return true;
+}
+
+const uint8_t* ExifUtilsImpl::getApp1Buffer() {
+    return app1_buffer_;
+}
+
+unsigned int ExifUtilsImpl::getApp1Length() {
+    return app1_length_;
+}
+
+bool ExifUtilsImpl::setExifVersion(const std::string& exif_version) {
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_EXIF_VERSION, EXIF_FORMAT_UNDEFINED, exif_version);
+    return true;
+}
+
+bool ExifUtilsImpl::setMake(const std::string& make) {
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_MAKE, EXIF_FORMAT_ASCII, make);
+    return true;
+}
+
+bool ExifUtilsImpl::setModel(const std::string& model) {
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_MODEL, EXIF_FORMAT_ASCII, model);
+    return true;
+}
+
+void ExifUtilsImpl::reset() {
+    destroyApp1();
+    if (exif_data_) {
+        /*
+         * Since we decided to ignore the original APP1, we are sure that there is
+         * no thumbnail allocated by libexif. |exif_data_->data| is actually
+         * allocated by JpegCompressor. sets |exif_data_->data| to nullptr to
+         * prevent exif_data_unref() destroy it incorrectly.
+         */
+        exif_data_->data = nullptr;
+        exif_data_->size = 0;
+        exif_data_unref(exif_data_);
+        exif_data_ = nullptr;
+    }
+}
+
+std::unique_ptr<ExifEntry> ExifUtilsImpl::addVariableLengthEntry(ExifIfd ifd,
+                                                                 ExifTag tag,
+                                                                 ExifFormat format,
+                                                                 uint64_t components,
+                                                                 unsigned int size) {
+    // Remove old entry if exists.
+    exif_content_remove_entry(exif_data_->ifd[ifd],
+                              exif_content_get_entry(exif_data_->ifd[ifd], tag));
+    ExifMem* mem = exif_mem_new_default();
+    if (!mem) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        return nullptr;
+    }
+    std::unique_ptr<ExifEntry> entry(exif_entry_new_mem(mem));
+    if (!entry) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        exif_mem_unref(mem);
+        return nullptr;
+    }
+    void* tmpBuffer = exif_mem_alloc(mem, size);
+    if (!tmpBuffer) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        exif_mem_unref(mem);
+        return nullptr;
+    }
+
+    entry->data = static_cast<unsigned char*>(tmpBuffer);
+    entry->tag = tag;
+    entry->format = format;
+    entry->components = components;
+    entry->size = size;
+
+    exif_content_add_entry(exif_data_->ifd[ifd], entry.get());
+    exif_mem_unref(mem);
+
+    return entry;
+}
+
+std::unique_ptr<ExifEntry> ExifUtilsImpl::addEntry(ExifIfd ifd, ExifTag tag) {
+    std::unique_ptr<ExifEntry> entry(exif_content_get_entry(exif_data_->ifd[ifd], tag));
+    if (entry) {
+        // exif_content_get_entry() won't ref the entry, so we ref here.
+        exif_entry_ref(entry.get());
+        return entry;
+    }
+    entry.reset(exif_entry_new());
+    if (!entry) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        return nullptr;
+    }
+    entry->tag = tag;
+    exif_content_add_entry(exif_data_->ifd[ifd], entry.get());
+    exif_entry_initialize(entry.get(), tag);
+    return entry;
+}
+
+bool ExifUtilsImpl::setShort(ExifIfd ifd,
+                             ExifTag tag,
+                             uint16_t value,
+                             const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_short(entry->data, EXIF_BYTE_ORDER_INTEL, value);
+    return true;
+}
+
+bool ExifUtilsImpl::setLong(ExifIfd ifd,
+                            ExifTag tag,
+                            uint32_t value,
+                            const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_long(entry->data, EXIF_BYTE_ORDER_INTEL, value);
+    return true;
+}
+
+bool ExifUtilsImpl::setRational(ExifIfd ifd,
+                                ExifTag tag,
+                                uint32_t numerator,
+                                uint32_t denominator,
+                                const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
+                                        {numerator, denominator});
+    return true;
+}
+
+bool ExifUtilsImpl::setSRational(ExifIfd ifd,
+                                 ExifTag tag,
+                                 int32_t numerator,
+                                 int32_t denominator,
+                                 const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_srational(entry->data, EXIF_BYTE_ORDER_INTEL,
+                                          {numerator, denominator});
+    return true;
+}
+
+bool ExifUtilsImpl::setString(ExifIfd ifd,
+                              ExifTag tag,
+                              ExifFormat format,
+                              const std::string& buffer,
+                              const std::string& msg) {
+    size_t entry_size = buffer.length();
+    // Since the exif format is undefined, NULL termination is not necessary.
+    if (format == EXIF_FORMAT_ASCII) {
+        entry_size++;
+    }
+    std::unique_ptr<ExifEntry> entry =
+            addVariableLengthEntry(ifd, tag, format, entry_size, entry_size);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    memcpy(entry->data, buffer.c_str(), entry_size);
+    return true;
+}
+
+void ExifUtilsImpl::destroyApp1() {
+    /*
+     * Since there is no API to access ExifMem in ExifData->priv, we use free
+     * here, which is the default free function in libexif. See
+     * exif_data_save_data() for detail.
+     */
+    free(app1_buffer_);
+    app1_buffer_ = nullptr;
+    app1_length_ = 0;
+}
+
+bool ExifUtilsImpl::setFromMetadata(const CameraMetadata& metadata,
+                                    const size_t imageWidth,
+                                    const size_t imageHeight) {
+    // How precise the float-to-rational conversion for EXIF tags would be.
+    constexpr int kRationalPrecision = 10000;
+    if (!setImageWidth(imageWidth) ||
+            !setImageHeight(imageHeight)) {
+        ALOGE("%s: setting image resolution failed.", __FUNCTION__);
+        return false;
+    }
+
+    struct timespec tp;
+    struct tm time_info;
+    bool time_available = clock_gettime(CLOCK_REALTIME, &tp) != -1;
+    localtime_r(&tp.tv_sec, &time_info);
+    if (!setDateTime(time_info)) {
+        ALOGE("%s: setting data time failed.", __FUNCTION__);
+        return false;
+    }
+
+    float focal_length;
+    camera_metadata_ro_entry entry = metadata.find(ANDROID_LENS_FOCAL_LENGTH);
+    if (entry.count) {
+        focal_length = entry.data.f[0];
+    } else {
+        ALOGE("%s: Cannot find focal length in metadata.", __FUNCTION__);
+        return false;
+    }
+    if (!setFocalLength(
+                    static_cast<uint32_t>(focal_length * kRationalPrecision),
+                    kRationalPrecision)) {
+        ALOGE("%s: setting focal length failed.", __FUNCTION__);
+        return false;
+    }
+
+    if (metadata.exists(ANDROID_JPEG_GPS_COORDINATES)) {
+        entry = metadata.find(ANDROID_JPEG_GPS_COORDINATES);
+        if (entry.count < 3) {
+            ALOGE("%s: Gps coordinates in metadata is not complete.", __FUNCTION__);
+            return false;
+        }
+        if (!setGpsLatitude(entry.data.d[0])) {
+            ALOGE("%s: setting gps latitude failed.", __FUNCTION__);
+            return false;
+        }
+        if (!setGpsLongitude(entry.data.d[1])) {
+            ALOGE("%s: setting gps longitude failed.", __FUNCTION__);
+            return false;
+        }
+        if (!setGpsAltitude(entry.data.d[2])) {
+            ALOGE("%s: setting gps altitude failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_JPEG_GPS_PROCESSING_METHOD)) {
+        entry = metadata.find(ANDROID_JPEG_GPS_PROCESSING_METHOD);
+        std::string method_str(reinterpret_cast<const char*>(entry.data.u8));
+        if (!setGpsProcessingMethod(method_str)) {
+            ALOGE("%s: setting gps processing method failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (time_available && metadata.exists(ANDROID_JPEG_GPS_TIMESTAMP)) {
+        entry = metadata.find(ANDROID_JPEG_GPS_TIMESTAMP);
+        time_t timestamp = static_cast<time_t>(entry.data.i64[0]);
+        if (gmtime_r(&timestamp, &time_info)) {
+            if (!setGpsTimestamp(time_info)) {
+                ALOGE("%s: setting gps timestamp failed.", __FUNCTION__);
+                return false;
+            }
+        } else {
+            ALOGE("%s: Time tranformation failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_JPEG_ORIENTATION)) {
+        entry = metadata.find(ANDROID_JPEG_ORIENTATION);
+        if (!setOrientation(entry.data.i32[0])) {
+            ALOGE("%s: setting orientation failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_SENSOR_EXPOSURE_TIME)) {
+        entry = metadata.find(ANDROID_SENSOR_EXPOSURE_TIME);
+        // int64_t of nanoseconds
+        if (!setExposureTime(entry.data.i64[0],1000000000u)) {
+            ALOGE("%s: setting exposure time failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_LENS_APERTURE)) {
+        const int kAperturePrecision = 10000;
+        entry = metadata.find(ANDROID_LENS_APERTURE);
+        if (!setFNumber(entry.data.f[0] * kAperturePrecision,
+                                                      kAperturePrecision)) {
+            ALOGE("%s: setting F number failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_FLASH_INFO_AVAILABLE)) {
+        entry = metadata.find(ANDROID_FLASH_INFO_AVAILABLE);
+        if (entry.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_FALSE) {
+            const uint32_t kNoFlashFunction = 0x20;
+            if (!setFlash(kNoFlashFunction)) {
+                ALOGE("%s: setting flash failed.", __FUNCTION__);
+                return false;
+            }
+        } else {
+            ALOGE("%s: Unsupported flash info: %d",__FUNCTION__, entry.data.u8[0]);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_CONTROL_AWB_MODE)) {
+        entry = metadata.find(ANDROID_CONTROL_AWB_MODE);
+        if (entry.data.u8[0] == ANDROID_CONTROL_AWB_MODE_AUTO) {
+            const uint16_t kAutoWhiteBalance = 0;
+            if (!setWhiteBalance(kAutoWhiteBalance)) {
+                ALOGE("%s: setting white balance failed.", __FUNCTION__);
+                return false;
+            }
+        } else {
+            ALOGE("%s: Unsupported awb mode: %d", __FUNCTION__, entry.data.u8[0]);
+            return false;
+        }
+    }
+
+    if (time_available) {
+        char str[4];
+        if (snprintf(str, sizeof(str), "%03ld", tp.tv_nsec / 1000000) < 0) {
+            ALOGE("%s: Subsec is invalid: %ld", __FUNCTION__, tp.tv_nsec);
+            return false;
+        }
+        if (!setSubsecTime(std::string(str))) {
+            ALOGE("%s: setting subsec time failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp
index e9741ef..21706a8 100644
--- a/camera/common/1.0/default/HandleImporter.cpp
+++ b/camera/common/1.0/default/HandleImporter.cpp
@@ -134,6 +134,38 @@
     }
 }
 
+void* HandleImporter::lock(
+        buffer_handle_t& buf, uint64_t cpuUsage, size_t size) {
+    Mutex::Autolock lock(mLock);
+    void *ret = 0;
+    IMapper::Rect accessRegion { 0, 0, static_cast<int>(size), 1 };
+
+    if (!mInitialized) {
+        initializeLocked();
+    }
+
+    if (mMapper == nullptr) {
+        ALOGE("%s: mMapper is null!", __FUNCTION__);
+        return ret;
+    }
+
+    hidl_handle acquireFenceHandle;
+    auto buffer = const_cast<native_handle_t*>(buf);
+    mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+            [&](const auto& tmpError, const auto& tmpPtr) {
+                if (tmpError == MapperError::NONE) {
+                    ret = tmpPtr;
+                } else {
+                    ALOGE("%s: failed to lock error %d!",
+                          __FUNCTION__, tmpError);
+                }
+           });
+
+    ALOGV("%s: ptr %p size: %zu", __FUNCTION__, ret, size);
+    return ret;
+}
+
+
 YCbCrLayout HandleImporter::lockYCbCr(
         buffer_handle_t& buf, uint64_t cpuUsage,
         const IMapper::Rect& accessRegion) {
diff --git a/camera/common/1.0/default/include/Exif.h b/camera/common/1.0/default/include/Exif.h
new file mode 100644
index 0000000..dc31679
--- /dev/null
+++ b/camera/common/1.0/default/include/Exif.h
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_CAMERA_COMMON_1_0_EXIF_H
+#define ANDROID_HARDWARE_INTERFACES_CAMERA_COMMON_1_0_EXIF_H
+
+#include "CameraMetadata.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+
+// This is based on the original ChromeOS ARC implementation of a V4L2 HAL
+
+// ExifUtils can generate APP1 segment with tags which caller set. ExifUtils can
+// also add a thumbnail in the APP1 segment if thumbnail size is specified.
+// ExifUtils can be reused with different images by calling initialize().
+//
+// Example of using this class :
+//  std::unique_ptr<ExifUtils> utils(ExifUtils::Create());
+//  utils->initialize();
+//  ...
+//  // Call ExifUtils functions to set Exif tags.
+//  ...
+//  utils->GenerateApp1(thumbnail_buffer, thumbnail_size);
+//  unsigned int app1Length = utils->GetApp1Length();
+//  uint8_t* app1Buffer = new uint8_t[app1Length];
+//  memcpy(app1Buffer, utils->GetApp1Buffer(), app1Length);
+class ExifUtils {
+
+ public:
+    virtual ~ExifUtils();
+
+    static ExifUtils* create();
+
+    // Initialize() can be called multiple times. The setting of Exif tags will be
+    // cleared.
+    virtual bool initialize() = 0;
+
+    // Set all known fields from a metadata structure
+    virtual bool setFromMetadata(const CameraMetadata& metadata,
+                                 const size_t imageWidth,
+                                 const size_t imageHeight) = 0;
+
+    // Sets the len aperture.
+    // Returns false if memory allocation fails.
+    virtual bool setAperture(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the value of brightness.
+    // Returns false if memory allocation fails.
+    virtual bool setBrightness(int32_t numerator, int32_t denominator) = 0;
+
+    // Sets the color space.
+    // Returns false if memory allocation fails.
+    virtual bool setColorSpace(uint16_t color_space) = 0;
+
+    // Sets the information to compressed data.
+    // Returns false if memory allocation fails.
+    virtual bool setComponentsConfiguration(const std::string& components_configuration) = 0;
+
+    // Sets the compression scheme used for the image data.
+    // Returns false if memory allocation fails.
+    virtual bool setCompression(uint16_t compression) = 0;
+
+    // Sets image contrast.
+    // Returns false if memory allocation fails.
+    virtual bool setContrast(uint16_t contrast) = 0;
+
+    // Sets the date and time of image last modified. It takes local time. The
+    // name of the tag is DateTime in IFD0.
+    // Returns false if memory allocation fails.
+    virtual bool setDateTime(const struct tm& t) = 0;
+
+    // Sets the image description.
+    // Returns false if memory allocation fails.
+    virtual bool setDescription(const std::string& description) = 0;
+
+    // Sets the digital zoom ratio. If the numerator is 0, it means digital zoom
+    // was not used.
+    // Returns false if memory allocation fails.
+    virtual bool setDigitalZoomRatio(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the exposure bias.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureBias(int32_t numerator, int32_t denominator) = 0;
+
+    // Sets the exposure mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureMode(uint16_t exposure_mode) = 0;
+
+    // Sets the program used by the camera to set exposure when the picture is
+    // taken.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureProgram(uint16_t exposure_program) = 0;
+
+    // Sets the exposure time, given in seconds.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureTime(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the status of flash.
+    // Returns false if memory allocation fails.
+    virtual bool setFlash(uint16_t flash) = 0;
+
+    // Sets the F number.
+    // Returns false if memory allocation fails.
+    virtual bool setFNumber(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the focal length of lens used to take the image in millimeters.
+    // Returns false if memory allocation fails.
+    virtual bool setFocalLength(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the degree of overall image gain adjustment.
+    // Returns false if memory allocation fails.
+    virtual bool setGainControl(uint16_t gain_control) = 0;
+
+    // Sets the altitude in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsAltitude(double altitude) = 0;
+
+    // Sets the latitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLatitude(double latitude) = 0;
+
+    // Sets the longitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLongitude(double longitude) = 0;
+
+    // Sets GPS processing method.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsProcessingMethod(const std::string& method) = 0;
+
+    // Sets GPS date stamp and time stamp (atomic clock). It takes UTC time.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsTimestamp(const struct tm& t) = 0;
+
+    // Sets the height (number of rows) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageHeight(uint32_t length) = 0;
+
+    // Sets the width (number of columns) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageWidth(uint32_t width) = 0;
+
+    // Sets the ISO speed.
+    // Returns false if memory allocation fails.
+    virtual bool setIsoSpeedRating(uint16_t iso_speed_ratings) = 0;
+
+    // Sets the kind of light source.
+    // Returns false if memory allocation fails.
+    virtual bool setLightSource(uint16_t light_source) = 0;
+
+    // Sets the smallest F number of the lens.
+    // Returns false if memory allocation fails.
+    virtual bool setMaxAperture(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the metering mode.
+    // Returns false if memory allocation fails.
+    virtual bool setMeteringMode(uint16_t metering_mode) = 0;
+
+    // Sets image orientation.
+    // Returns false if memory allocation fails.
+    virtual bool setOrientation(uint16_t orientation) = 0;
+
+    // Sets the unit for measuring XResolution and YResolution.
+    // Returns false if memory allocation fails.
+    virtual bool setResolutionUnit(uint16_t resolution_unit) = 0;
+
+    // Sets image saturation.
+    // Returns false if memory allocation fails.
+    virtual bool setSaturation(uint16_t saturation) = 0;
+
+    // Sets the type of scene that was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setSceneCaptureType(uint16_t type) = 0;
+
+    // Sets image sharpness.
+    // Returns false if memory allocation fails.
+    virtual bool setSharpness(uint16_t sharpness) = 0;
+
+    // Sets the shutter speed.
+    // Returns false if memory allocation fails.
+    virtual bool setShutterSpeed(int32_t numerator, int32_t denominator) = 0;
+
+    // Sets the distance to the subject, given in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setSubjectDistance(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the fractions of seconds for the <DateTime> tag.
+    // Returns false if memory allocation fails.
+    virtual bool setSubsecTime(const std::string& subsec_time) = 0;
+
+    // Sets the white balance mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setWhiteBalance(uint16_t white_balance) = 0;
+
+    // Sets the number of pixels per resolution unit in the image width.
+    // Returns false if memory allocation fails.
+    virtual bool setXResolution(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the position of chrominance components in relation to the luminance
+    // component.
+    // Returns false if memory allocation fails.
+    virtual bool setYCbCrPositioning(uint16_t ycbcr_positioning) = 0;
+
+    // Sets the number of pixels per resolution unit in the image length.
+    // Returns false if memory allocation fails.
+    virtual bool setYResolution(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the manufacturer of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setMake(const std::string& make) = 0;
+
+    // Sets the model number of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setModel(const std::string& model) = 0;
+
+    // Generates APP1 segment.
+    // Returns false if generating APP1 segment fails.
+    virtual bool generateApp1(const void* thumbnail_buffer, uint32_t size) = 0;
+
+    // Gets buffer of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual const uint8_t* getApp1Buffer() = 0;
+
+    // Gets length of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual unsigned int getApp1Length() = 0;
+};
+
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+
+#endif  // ANDROID_HARDWARE_INTERFACES_CAMERA_COMMON_1_0_EXIF_H
diff --git a/camera/common/1.0/default/include/HandleImporter.h b/camera/common/1.0/default/include/HandleImporter.h
index 443362d..f9cd9fb 100644
--- a/camera/common/1.0/default/include/HandleImporter.h
+++ b/camera/common/1.0/default/include/HandleImporter.h
@@ -45,6 +45,9 @@
     void closeFence(int fd) const;
 
     // Assume caller has done waiting for acquire fences
+    void* lock(buffer_handle_t& buf, uint64_t cpuUsage, size_t size);
+
+    // Assume caller has done waiting for acquire fences
     YCbCrLayout lockYCbCr(buffer_handle_t& buf, uint64_t cpuUsage,
                           const IMapper::Rect& accessRegion);
 
diff --git a/camera/device/3.4/default/Android.bp b/camera/device/3.4/default/Android.bp
index 61ac244..a936dae 100644
--- a/camera/device/3.4/default/Android.bp
+++ b/camera/device/3.4/default/Android.bp
@@ -34,7 +34,7 @@
     srcs: [
         "CameraDevice.cpp",
         "CameraDeviceSession.cpp",
-        "convert.cpp",
+        "convert.cpp"
     ],
     shared_libs: [
         "libhidlbase",
@@ -89,6 +89,8 @@
         "libfmq",
         "libsync",
         "libyuv",
+        "libjpeg",
+        "libexif",
     ],
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index c1f6114..e6e0ae3 100644
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -47,7 +47,7 @@
 //       Also make sure that can be done without editing source code
 
 // TODO: b/72261675: make it dynamic since this affects memory usage
-const int kMaxJpegSize = {13 * 1024 * 1024};  // 13MB
+const int kMaxJpegSize = {5 * 1024 * 1024};  // 5MB
 } // anonymous namespace
 
 ExternalCameraDevice::ExternalCameraDevice(const std::string& cameraId) :
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index 2face78..ff55489 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -30,6 +30,9 @@
 #define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
 #include <libyuv.h>
 
+#include <jpeglib.h>
+
+
 namespace android {
 namespace hardware {
 namespace camera {
@@ -73,7 +76,9 @@
         mV4l2Fd(std::move(v4l2Fd)),
         mSupportedFormats(sortFormats(supportedFormats)),
         mCroppingType(initCroppingType(mSupportedFormats)),
-        mOutputThread(new OutputThread(this, mCroppingType)) {
+        mOutputThread(new OutputThread(this, mCroppingType)),
+        mMaxThumbResolution(getMaxThumbResolution()),
+        mMaxJpegResolution(getMaxJpegResolution()) {
     mInitFail = initialize();
 }
 
@@ -779,9 +784,9 @@
 }
 
 int ExternalCameraDeviceSession::OutputThread::cropAndScaleLocked(
-        sp<AllocatedFrame>& in, const HalStreamBuffer& halBuf, YCbCrLayout* out) {
+        sp<AllocatedFrame>& in, const Size& outSz, YCbCrLayout* out) {
     Size inSz = {in->mWidth, in->mHeight};
-    Size outSz = {halBuf.width, halBuf.height};
+
     int ret;
     if (inSz == outSz) {
         ret = in->getLayout(out);
@@ -869,6 +874,152 @@
     return 0;
 }
 
+
+int ExternalCameraDeviceSession::OutputThread::cropAndScaleThumbLocked(
+        sp<AllocatedFrame>& in, const Size &outSz, YCbCrLayout* out) {
+    Size inSz  {in->mWidth, in->mHeight};
+
+    if ((outSz.width * outSz.height) >
+        (mYu12ThumbFrame->mWidth * mYu12ThumbFrame->mHeight)) {
+        ALOGE("%s: Requested thumbnail size too big (%d,%d) > (%d,%d)",
+              __FUNCTION__, outSz.width, outSz.height,
+              mYu12ThumbFrame->mWidth, mYu12ThumbFrame->mHeight);
+        return -1;
+    }
+
+    int ret;
+
+    /* This will crop-and-zoom the input YUV frame to the thumbnail size
+     * Based on the following logic:
+     *  1) Square pixels come in, square pixels come out, therefore single
+     *  scale factor is computed to either make input bigger or smaller
+     *  depending on if we are upscaling or downscaling
+     *  2) That single scale factor would either make height too tall or width
+     *  too wide so we need to crop the input either horizontally or vertically
+     *  but not both
+     */
+
+    /* Convert the input and output dimensions into floats for ease of math */
+    float fWin = static_cast<float>(inSz.width);
+    float fHin = static_cast<float>(inSz.height);
+    float fWout = static_cast<float>(outSz.width);
+    float fHout = static_cast<float>(outSz.height);
+
+    /* Compute the one scale factor from (1) above, it will be the smaller of
+     * the two possibilities. */
+    float scaleFactor = std::min( fHin / fHout, fWin / fWout );
+
+    /* Since we are crop-and-zooming (as opposed to letter/pillar boxing) we can
+     * simply multiply the output by our scaleFactor to get the cropped input
+     * size. Note that at least one of {fWcrop, fHcrop} is going to wind up
+     * being {fWin, fHin} respectively because fHout or fWout cancels out the
+     * scaleFactor calculation above.
+     *
+     * Specifically:
+     *  if ( fHin / fHout ) < ( fWin / fWout ) we crop the sides off
+     * input, in which case
+     *    scaleFactor = fHin / fHout
+     *    fWcrop = fHin / fHout * fWout
+     *    fHcrop = fHin
+     *
+     * Note that fWcrop <= fWin ( because ( fHin / fHout ) * fWout < fWin, which
+     * is just the inequality above with both sides multiplied by fWout
+     *
+     * on the other hand if ( fWin / fWout ) < ( fHin / fHout) we crop the top
+     * and the bottom off of input, and
+     *    scaleFactor = fWin / fWout
+     *    fWcrop = fWin
+     *    fHCrop = fWin / fWout * fHout
+     */
+    float fWcrop = scaleFactor * fWout;
+    float fHcrop = scaleFactor * fHout;
+
+    /* Convert to integer and truncate to an even number */
+    Size cropSz = { 2*static_cast<uint32_t>(fWcrop/2.0f),
+                    2*static_cast<uint32_t>(fHcrop/2.0f) };
+
+    /* Convert to a centered rectange with even top/left */
+    IMapper::Rect inputCrop {
+        2*static_cast<int32_t>((inSz.width - cropSz.width)/4),
+        2*static_cast<int32_t>((inSz.height - cropSz.height)/4),
+        static_cast<int32_t>(cropSz.width),
+        static_cast<int32_t>(cropSz.height) };
+
+    if ((inputCrop.top < 0) ||
+        (inputCrop.top >= static_cast<int32_t>(inSz.height)) ||
+        (inputCrop.left < 0) ||
+        (inputCrop.left >= static_cast<int32_t>(inSz.width)) ||
+        (inputCrop.width <= 0) ||
+        (inputCrop.width + inputCrop.left > static_cast<int32_t>(inSz.width)) ||
+        (inputCrop.height <= 0) ||
+        (inputCrop.height + inputCrop.top > static_cast<int32_t>(inSz.height)))
+    {
+        ALOGE("%s: came up with really wrong crop rectangle",__FUNCTION__);
+        ALOGE("%s: input layout %dx%d to for output size %dx%d",
+             __FUNCTION__, inSz.width, inSz.height, outSz.width, outSz.height);
+        ALOGE("%s: computed input crop +%d,+%d %dx%d",
+             __FUNCTION__, inputCrop.left, inputCrop.top,
+             inputCrop.width, inputCrop.height);
+        return -1;
+    }
+
+    YCbCrLayout inputLayout;
+    ret = in->getCroppedLayout(inputCrop, &inputLayout);
+    if (ret != 0) {
+        ALOGE("%s: failed to crop input layout %dx%d to for output size %dx%d",
+             __FUNCTION__, inSz.width, inSz.height, outSz.width, outSz.height);
+        ALOGE("%s: computed input crop +%d,+%d %dx%d",
+             __FUNCTION__, inputCrop.left, inputCrop.top,
+             inputCrop.width, inputCrop.height);
+        return ret;
+    }
+    ALOGV("%s: crop input layout %dx%d to for output size %dx%d",
+          __FUNCTION__, inSz.width, inSz.height, outSz.width, outSz.height);
+    ALOGV("%s: computed input crop +%d,+%d %dx%d",
+          __FUNCTION__, inputCrop.left, inputCrop.top,
+          inputCrop.width, inputCrop.height);
+
+
+    // Scale
+    YCbCrLayout outFullLayout;
+
+    ret = mYu12ThumbFrame->getLayout(&outFullLayout);
+    if (ret != 0) {
+        ALOGE("%s: failed to get output buffer layout", __FUNCTION__);
+        return ret;
+    }
+
+
+    ret = libyuv::I420Scale(
+            static_cast<uint8_t*>(inputLayout.y),
+            inputLayout.yStride,
+            static_cast<uint8_t*>(inputLayout.cb),
+            inputLayout.cStride,
+            static_cast<uint8_t*>(inputLayout.cr),
+            inputLayout.cStride,
+            inputCrop.width,
+            inputCrop.height,
+            static_cast<uint8_t*>(outFullLayout.y),
+            outFullLayout.yStride,
+            static_cast<uint8_t*>(outFullLayout.cb),
+            outFullLayout.cStride,
+            static_cast<uint8_t*>(outFullLayout.cr),
+            outFullLayout.cStride,
+            outSz.width,
+            outSz.height,
+            libyuv::FilterMode::kFilterNone);
+
+    if (ret != 0) {
+        ALOGE("%s: failed to scale buffer from %dx%d to %dx%d. Ret %d",
+                __FUNCTION__, inputCrop.width, inputCrop.height,
+                outSz.width, outSz.height, ret);
+        return ret;
+    }
+
+    *out = outFullLayout;
+    return 0;
+}
+
 int ExternalCameraDeviceSession::OutputThread::formatConvertLocked(
         const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) {
     int ret = 0;
@@ -951,6 +1102,436 @@
     return 0;
 }
 
+int ExternalCameraDeviceSession::OutputThread::encodeJpegYU12(
+        const Size & inSz, const YCbCrLayout& inLayout,
+        int jpegQuality, const void *app1Buffer, size_t app1Size,
+        void *out, const size_t maxOutSize, size_t &actualCodeSize)
+{
+    /* libjpeg is a C library so we use C-style "inheritance" by
+     * putting libjpeg's jpeg_destination_mgr first in our custom
+     * struct. This allows us to cast jpeg_destination_mgr* to
+     * CustomJpegDestMgr* when we get it passed to us in a callback */
+    struct CustomJpegDestMgr {
+        struct jpeg_destination_mgr mgr;
+        JOCTET *mBuffer;
+        size_t mBufferSize;
+        size_t mEncodedSize;
+        bool mSuccess;
+    } dmgr;
+
+    jpeg_compress_struct cinfo = {};
+    jpeg_error_mgr jerr;
+
+    /* Initialize error handling with standard callbacks, but
+     * then override output_message (to print to ALOG) and
+     * error_exit to set a flag and print a message instead
+     * of killing the whole process */
+    cinfo.err = jpeg_std_error(&jerr);
+
+    cinfo.err->output_message = [](j_common_ptr cinfo) {
+        char buffer[JMSG_LENGTH_MAX];
+
+        /* Create the message */
+        (*cinfo->err->format_message)(cinfo, buffer);
+        ALOGE("libjpeg error: %s", buffer);
+    };
+    cinfo.err->error_exit = [](j_common_ptr cinfo) {
+        (*cinfo->err->output_message)(cinfo);
+        if(cinfo->client_data) {
+            auto & dmgr =
+                *reinterpret_cast<CustomJpegDestMgr*>(cinfo->client_data);
+            dmgr.mSuccess = false;
+        }
+    };
+    /* Now that we initialized some callbacks, let's create our compressor */
+    jpeg_create_compress(&cinfo);
+
+    /* Initialize our destination manager */
+    dmgr.mBuffer = static_cast<JOCTET*>(out);
+    dmgr.mBufferSize = maxOutSize;
+    dmgr.mEncodedSize = 0;
+    dmgr.mSuccess = true;
+    cinfo.client_data = static_cast<void*>(&dmgr);
+
+    /* These lambdas become C-style function pointers and as per C++11 spec
+     * may not capture anything */
+    dmgr.mgr.init_destination = [](j_compress_ptr cinfo) {
+        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+        dmgr.mgr.next_output_byte = dmgr.mBuffer;
+        dmgr.mgr.free_in_buffer = dmgr.mBufferSize;
+        ALOGV("%s:%d jpeg start: %p [%zu]",
+              __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
+    };
+
+    dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
+        ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
+        return 0;
+    };
+
+    dmgr.mgr.term_destination = [](j_compress_ptr cinfo) {
+        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+        dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer;
+        ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
+    };
+    cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
+
+    /* We are going to be using JPEG in raw data mode, so we are passing
+     * straight subsampled planar YCbCr and it will not touch our pixel
+     * data or do any scaling or anything */
+    cinfo.image_width = inSz.width;
+    cinfo.image_height = inSz.height;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_YCbCr;
+
+    /* Initialize defaults and then override what we want */
+    jpeg_set_defaults(&cinfo);
+
+    jpeg_set_quality(&cinfo, jpegQuality, 1);
+    jpeg_set_colorspace(&cinfo, JCS_YCbCr);
+    cinfo.raw_data_in = 1;
+    cinfo.dct_method = JDCT_IFAST;
+
+    /* Configure sampling factors. The sampling factor is JPEG subsampling 420
+     * because the source format is YUV420. Note that libjpeg sampling factors
+     * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and
+     * 1 V value for each 2 Y values */
+    cinfo.comp_info[0].h_samp_factor = 2;
+    cinfo.comp_info[0].v_samp_factor = 2;
+    cinfo.comp_info[1].h_samp_factor = 1;
+    cinfo.comp_info[1].v_samp_factor = 1;
+    cinfo.comp_info[2].h_samp_factor = 1;
+    cinfo.comp_info[2].v_samp_factor = 1;
+
+    /* Let's not hardcode YUV420 in 6 places... 5 was enough */
+    int maxVSampFactor = std::max( {
+        cinfo.comp_info[0].v_samp_factor,
+        cinfo.comp_info[1].v_samp_factor,
+        cinfo.comp_info[2].v_samp_factor
+    });
+    int cVSubSampling = cinfo.comp_info[0].v_samp_factor /
+                        cinfo.comp_info[1].v_samp_factor;
+
+    /* Start the compressor */
+    jpeg_start_compress(&cinfo, TRUE);
+
+    /* Compute our macroblock height, so we can pad our input to be vertically
+     * macroblock aligned.
+     * TODO: Does it need to be horizontally MCU aligned too? */
+
+    size_t mcuV = DCTSIZE*maxVSampFactor;
+    size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV);
+
+    /* libjpeg uses arrays of row pointers, which makes it really easy to pad
+     * data vertically (unfortunately doesn't help horizontally) */
+    std::vector<JSAMPROW> yLines (paddedHeight);
+    std::vector<JSAMPROW> cbLines(paddedHeight/cVSubSampling);
+    std::vector<JSAMPROW> crLines(paddedHeight/cVSubSampling);
+
+    uint8_t *py = static_cast<uint8_t*>(inLayout.y);
+    uint8_t *pcr = static_cast<uint8_t*>(inLayout.cr);
+    uint8_t *pcb = static_cast<uint8_t*>(inLayout.cb);
+
+    for(uint32_t i = 0; i < paddedHeight; i++)
+    {
+        /* Once we are in the padding territory we still point to the last line
+         * effectively replicating it several times ~ CLAMP_TO_EDGE */
+        int li = std::min(i, inSz.height - 1);
+        yLines[i]  = static_cast<JSAMPROW>(py + li * inLayout.yStride);
+        if(i < paddedHeight / cVSubSampling)
+        {
+            crLines[i] = static_cast<JSAMPROW>(pcr + li * inLayout.cStride);
+            cbLines[i] = static_cast<JSAMPROW>(pcb + li * inLayout.cStride);
+        }
+    }
+
+    /* If APP1 data was passed in, use it */
+    if(app1Buffer && app1Size)
+    {
+        jpeg_write_marker(&cinfo, JPEG_APP0 + 1,
+             static_cast<const JOCTET*>(app1Buffer), app1Size);
+    }
+
+    /* While we still have padded height left to go, keep giving it one
+     * macroblock at a time. */
+    while (cinfo.next_scanline < cinfo.image_height) {
+        const uint32_t batchSize = DCTSIZE * maxVSampFactor;
+        const uint32_t nl = cinfo.next_scanline;
+        JSAMPARRAY planes[3]{ &yLines[nl],
+                              &cbLines[nl/cVSubSampling],
+                              &crLines[nl/cVSubSampling] };
+
+        uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize);
+
+        if (done != batchSize) {
+            ALOGE("%s: compressed %u lines, expected %u (total %u/%u)",
+              __FUNCTION__, done, batchSize, cinfo.next_scanline,
+              cinfo.image_height);
+            return -1;
+        }
+    }
+
+    /* This will flush everything */
+    jpeg_finish_compress(&cinfo);
+
+    /* Grab the actual code size and set it */
+    actualCodeSize = dmgr.mEncodedSize;
+
+    return 0;
+}
+
+/*
+ * TODO: There needs to be a mechanism to discover allocated buffer size
+ * in the HAL.
+ *
+ * This is very fragile because it is duplicated computation from:
+ * frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
+ *
+ */
+
+/* This assumes mSupportedFormats have all been declared as supporting
+ * HAL_PIXEL_FORMAT_BLOB to the framework */
+Size ExternalCameraDeviceSession::getMaxJpegResolution() const {
+    Size ret { 0, 0 };
+    for(auto & fmt : mSupportedFormats) {
+        if(fmt.width * fmt.height > ret.width * ret.height) {
+            ret = Size { fmt.width, fmt.height };
+        }
+    }
+    return ret;
+}
+
+Size ExternalCameraDeviceSession::getMaxThumbResolution() const {
+    Size thumbSize { 0, 0 };
+    camera_metadata_ro_entry entry =
+        mCameraCharacteristics.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+    for(uint32_t i = 0; i < entry.count; i += 2) {
+        Size sz { static_cast<uint32_t>(entry.data.i32[i]),
+                  static_cast<uint32_t>(entry.data.i32[i+1]) };
+        if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
+            thumbSize = sz;
+        }
+    }
+
+    if (thumbSize.width * thumbSize.height == 0) {
+        ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__);
+    }
+
+    return thumbSize;
+}
+
+
+ssize_t ExternalCameraDeviceSession::getJpegBufferSize(
+        uint32_t width, uint32_t height) const {
+    // Constant from camera3.h
+    const ssize_t kMinJpegBufferSize = 256 * 1024 + sizeof(CameraBlob);
+    // Get max jpeg size (area-wise).
+    if (mMaxJpegResolution.width == 0) {
+        ALOGE("%s: Do not have a single supported JPEG stream",
+                __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    // Get max jpeg buffer size
+    ssize_t maxJpegBufferSize = 0;
+    camera_metadata_ro_entry jpegBufMaxSize =
+            mCameraCharacteristics.find(ANDROID_JPEG_MAX_SIZE);
+    if (jpegBufMaxSize.count == 0) {
+        ALOGE("%s: Can't find maximum JPEG size in static metadata!",
+              __FUNCTION__);
+        return BAD_VALUE;
+    }
+    maxJpegBufferSize = jpegBufMaxSize.data.i32[0];
+
+    if (maxJpegBufferSize <= kMinJpegBufferSize) {
+        ALOGE("%s: ANDROID_JPEG_MAX_SIZE (%zd) <= kMinJpegBufferSize (%zd)",
+              __FUNCTION__, maxJpegBufferSize, kMinJpegBufferSize);
+        return BAD_VALUE;
+    }
+
+    // Calculate final jpeg buffer size for the given resolution.
+    float scaleFactor = ((float) (width * height)) /
+            (mMaxJpegResolution.width * mMaxJpegResolution.height);
+    ssize_t jpegBufferSize = scaleFactor * (maxJpegBufferSize - kMinJpegBufferSize) +
+            kMinJpegBufferSize;
+    if (jpegBufferSize > maxJpegBufferSize) {
+        jpegBufferSize = maxJpegBufferSize;
+    }
+
+    return jpegBufferSize;
+}
+
+int ExternalCameraDeviceSession::OutputThread::createJpegLocked(
+        HalStreamBuffer &halBuf,
+        HalRequest &req)
+{
+    int ret;
+    auto lfail = [&](auto... args) {
+        ALOGE(args...);
+
+        return 1;
+    };
+    auto parent = mParent.promote();
+    if (parent == nullptr) {
+       ALOGE("%s: session has been disconnected!", __FUNCTION__);
+       return 1;
+    }
+
+    ALOGV("%s: HAL buffer sid: %d bid: %" PRIu64 " w: %u h: %u",
+          __FUNCTION__, halBuf.streamId, static_cast<uint64_t>(halBuf.bufferId),
+          halBuf.width, halBuf.height);
+    ALOGV("%s: HAL buffer fmt: %x usage: %" PRIx64 " ptr: %p",
+          __FUNCTION__, halBuf.format, static_cast<uint64_t>(halBuf.usage),
+          halBuf.bufPtr);
+    ALOGV("%s: YV12 buffer %d x %d",
+          __FUNCTION__,
+          mYu12Frame->mWidth, mYu12Frame->mHeight);
+
+    int jpegQuality, thumbQuality;
+    Size thumbSize;
+
+    if (req.setting.exists(ANDROID_JPEG_QUALITY)) {
+        camera_metadata_entry entry =
+            req.setting.find(ANDROID_JPEG_QUALITY);
+        jpegQuality = entry.data.u8[0];
+    } else {
+        return lfail("%s: ANDROID_JPEG_QUALITY not set",__FUNCTION__);
+    }
+
+    if (req.setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
+        camera_metadata_entry entry =
+            req.setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
+        thumbQuality = entry.data.u8[0];
+    } else {
+        return lfail(
+            "%s: ANDROID_JPEG_THUMBNAIL_QUALITY not set",
+            __FUNCTION__);
+    }
+
+    if (req.setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
+        camera_metadata_entry entry =
+            req.setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
+        thumbSize = Size { static_cast<uint32_t>(entry.data.i32[0]),
+                           static_cast<uint32_t>(entry.data.i32[1])
+        };
+    } else {
+        return lfail(
+            "%s: ANDROID_JPEG_THUMBNAIL_SIZE not set", __FUNCTION__);
+    }
+
+    /* Cropped and scaled YU12 buffer for main and thumbnail */
+    YCbCrLayout yu12Main;
+    Size jpegSize { halBuf.width, halBuf.height };
+
+    /* Compute temporary buffer sizes accounting for the following:
+     * thumbnail can't exceed APP1 size of 64K
+     * main image needs to hold APP1, headers, and at most a poorly
+     * compressed image */
+    const ssize_t maxThumbCodeSize = 64 * 1024;
+    const ssize_t maxJpegCodeSize = parent->getJpegBufferSize(jpegSize.width,
+                                                             jpegSize.height);
+
+    /* Check that getJpegBufferSize did not return an error */
+    if (maxJpegCodeSize < 0) {
+        return lfail(
+            "%s: getJpegBufferSize returned %zd",__FUNCTION__,maxJpegCodeSize);
+    }
+
+
+    /* Hold actual thumbnail and main image code sizes */
+    size_t thumbCodeSize = 0, jpegCodeSize = 0;
+    /* Temporary thumbnail code buffer */
+    std::vector<uint8_t> thumbCode(maxThumbCodeSize);
+
+    YCbCrLayout yu12Thumb;
+    ret = cropAndScaleThumbLocked(mYu12Frame, thumbSize, &yu12Thumb);
+
+    if (ret != 0) {
+        return lfail(
+            "%s: crop and scale thumbnail failed!", __FUNCTION__);
+    }
+
+    /* Scale and crop main jpeg */
+    ret = cropAndScaleLocked(mYu12Frame, jpegSize, &yu12Main);
+
+    if (ret != 0) {
+        return lfail("%s: crop and scale main failed!", __FUNCTION__);
+    }
+
+    /* Encode the thumbnail image */
+    ret = encodeJpegYU12(thumbSize, yu12Thumb,
+            thumbQuality, 0, 0,
+            &thumbCode[0], maxThumbCodeSize, thumbCodeSize);
+
+    if (ret != 0) {
+        return lfail("%s: encodeJpegYU12 failed with %d",__FUNCTION__, ret);
+    }
+
+    /* Combine camera characteristics with request settings to form EXIF
+     * metadata */
+    common::V1_0::helper::CameraMetadata meta(parent->mCameraCharacteristics);
+    meta.append(req.setting);
+
+    /* Generate EXIF object */
+    std::unique_ptr<ExifUtils> utils(ExifUtils::create());
+    /* Make sure it's initialized */
+    utils->initialize();
+
+    utils->setFromMetadata(meta, jpegSize.width, jpegSize.height);
+
+    /* Check if we made a non-zero-sized thumbnail. Currently not possible
+     * that we got this far and the code is size 0, but if this code moves
+     * around it might become relevant again */
+
+    ret = utils->generateApp1(thumbCodeSize ? &thumbCode[0] : 0, thumbCodeSize);
+
+    if (!ret) {
+        return lfail("%s: generating APP1 failed", __FUNCTION__);
+    }
+
+    /* Get internal buffer */
+    size_t exifDataSize = utils->getApp1Length();
+    const uint8_t* exifData = utils->getApp1Buffer();
+
+    /* Lock the HAL jpeg code buffer */
+    void *bufPtr = sHandleImporter.lock(
+            *(halBuf.bufPtr), halBuf.usage, maxJpegCodeSize);
+
+    if (!bufPtr) {
+        return lfail("%s: could not lock %zu bytes", __FUNCTION__, maxJpegCodeSize);
+    }
+
+    /* Encode the main jpeg image */
+    ret = encodeJpegYU12(jpegSize, yu12Main,
+            jpegQuality, exifData, exifDataSize,
+            bufPtr, maxJpegCodeSize, jpegCodeSize);
+
+    /* TODO: Not sure this belongs here, maybe better to pass jpegCodeSize out
+     * and do this when returning buffer to parent */
+    CameraBlob blob { CameraBlobId::JPEG, static_cast<uint32_t>(jpegCodeSize) };
+    void *blobDst =
+        reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(bufPtr) +
+                           maxJpegCodeSize -
+                           sizeof(CameraBlob));
+    memcpy(blobDst, &blob, sizeof(CameraBlob));
+
+    /* Unlock the HAL jpeg code buffer */
+    int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+    if (relFence > 0) {
+        halBuf.acquireFence = relFence;
+    }
+
+    /* Check if our JPEG actually succeeded */
+    if (ret != 0) {
+        return lfail(
+            "%s: encodeJpegYU12 failed with %d",__FUNCTION__, ret);
+    }
+
+    ALOGV("%s: encoded JPEG (ret:%d) with Q:%d max size: %zu",
+          __FUNCTION__, ret, jpegQuality, maxJpegCodeSize);
+
+    return 0;
+}
+
 bool ExternalCameraDeviceSession::OutputThread::threadLoop() {
     HalRequest req;
     auto parent = mParent.promote();
@@ -1031,9 +1612,21 @@
 
         // Gralloc lockYCbCr the buffer
         switch (halBuf.format) {
-            case PixelFormat::BLOB:
-                // TODO: b/72261675 implement JPEG output path
-                break;
+            case PixelFormat::BLOB: {
+                int ret = createJpegLocked(halBuf, req);
+
+                if(ret != 0) {
+                    ALOGE("%s: createJpegLocked failed with %d",
+                          __FUNCTION__, ret);
+                    lk.unlock();
+                    parent->notifyError(
+                            /*frameNum*/req.frameNumber,
+                            /*stream*/-1,
+                            ErrorCode::ERROR_DEVICE);
+
+                    return false;
+                }
+            } break;
             case PixelFormat::YCBCR_420_888:
             case PixelFormat::YV12: {
                 IMapper::Rect outRect {0, 0,
@@ -1055,7 +1648,9 @@
 
                 YCbCrLayout cropAndScaled;
                 int ret = cropAndScaleLocked(
-                        mYu12Frame, halBuf, &cropAndScaled);
+                        mYu12Frame,
+                        Size { halBuf.width, halBuf.height },
+                        &cropAndScaled);
                 if (ret != 0) {
                     ALOGE("%s: crop and scale failed!", __FUNCTION__);
                     lk.unlock();
@@ -1101,7 +1696,8 @@
 }
 
 Status ExternalCameraDeviceSession::OutputThread::allocateIntermediateBuffers(
-        const Size& v4lSize, const hidl_vec<Stream>& streams) {
+        const Size& v4lSize, const Size& thumbSize,
+        const hidl_vec<Stream>& streams) {
     std::lock_guard<std::mutex> lk(mLock);
     if (mScaledYu12Frames.size() != 0) {
         ALOGE("%s: intermediate buffer pool has %zu inflight buffers! (expect 0)",
@@ -1121,6 +1717,19 @@
         }
     }
 
+    // Allocating intermediate YU12 thumbnail frame
+    if (mYu12ThumbFrame == nullptr ||
+        mYu12ThumbFrame->mWidth != thumbSize.width ||
+        mYu12ThumbFrame->mHeight != thumbSize.height) {
+        mYu12ThumbFrame.clear();
+        mYu12ThumbFrame = new AllocatedFrame(thumbSize.width, thumbSize.height);
+        int ret = mYu12ThumbFrame->allocate(&mYu12ThumbFrameLayout);
+        if (ret != 0) {
+            ALOGE("%s: allocating YU12 thumb frame failed!", __FUNCTION__);
+            return Status::INTERNAL_ERROR;
+        }
+    }
+
     // Allocating scaled buffers
     for (const auto& stream : streams) {
         Size sz = {stream.width, stream.height};
@@ -1660,7 +2269,24 @@
     }
 
     Size v4lSize = {v4l2Fmt.width, v4l2Fmt.height};
-    status = mOutputThread->allocateIntermediateBuffers(v4lSize, config.streams);
+    Size thumbSize { 0, 0 };
+    camera_metadata_ro_entry entry =
+        mCameraCharacteristics.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+    for(uint32_t i = 0; i < entry.count; i += 2) {
+        Size sz { static_cast<uint32_t>(entry.data.i32[i]),
+                  static_cast<uint32_t>(entry.data.i32[i+1]) };
+        if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
+            thumbSize = sz;
+        }
+    }
+
+    if (thumbSize.width * thumbSize.height == 0) {
+        ALOGE("%s: non-zero thumbnail size not available", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+
+    status = mOutputThread->allocateIntermediateBuffers(v4lSize,
+                mMaxThumbResolution, config.streams);
     if (status != Status::OK) {
         ALOGE("%s: allocating intermediate buffers failed!", __FUNCTION__);
         return status;
@@ -1681,6 +2307,7 @@
         switch (config.streams[i].format) {
             case PixelFormat::BLOB:
             case PixelFormat::YCBCR_420_888:
+            case PixelFormat::YV12: // Used by SurfaceTexture
                 // No override
                 out->streams[i].v3_2.overrideFormat = config.streams[i].format;
                 break;
@@ -1693,7 +2320,7 @@
                 mStreamMap[config.streams[i].id].format = out->streams[i].v3_2.overrideFormat;
                 break;
             default:
-                ALOGE("%s: unsupported format %x", __FUNCTION__, config.streams[i].format);
+                ALOGE("%s: unsupported format 0x%x", __FUNCTION__, config.streams[i].format);
                 return Status::ILLEGAL_ARGUMENT;
         }
     }
@@ -1819,8 +2446,8 @@
                 intent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;
                 break;
             default:
-                ALOGE("%s: unknown template type %d", __FUNCTION__, type);
-                return BAD_VALUE;
+                ALOGV("%s: unsupported RequestTemplate type %d", __FUNCTION__, type);
+                continue;
         }
         UPDATE(mdCopy, ANDROID_CONTROL_CAPTURE_INTENT, &intent, 1);
 
@@ -1847,15 +2474,14 @@
     const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
     UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
 
-
-    // TODO: b/72261912 AF should stay LOCKED until cancel is seen
-    bool afTrigger = false;
+    bool afTrigger = mAfTrigger;
     if (md.exists(ANDROID_CONTROL_AF_TRIGGER)) {
+        Mutex::Autolock _l(mLock);
         camera_metadata_entry entry = md.find(ANDROID_CONTROL_AF_TRIGGER);
         if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_START) {
-            afTrigger = true;
+            mAfTrigger = afTrigger = true;
         } else if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_CANCEL) {
-            afTrigger = false;
+            mAfTrigger = afTrigger = false;
         }
     }
 
@@ -1885,6 +2511,9 @@
         return -EINVAL;
     }
 
+    const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
+    UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
+
     // android.scaler
     const int32_t crop_region[] = {
           active_array_size.data.i32[0], active_array_size.data.i32[1],
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
index d8a17f6..5856306 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
@@ -30,6 +30,7 @@
 #include <unordered_set>
 #include "CameraMetadata.h"
 #include "HandleImporter.h"
+#include "Exif.h"
 #include "utils/KeyedVector.h"
 #include "utils/Mutex.h"
 #include "utils/Thread.h"
@@ -58,10 +59,13 @@
 using ::android::hardware::camera::device::V3_2::StreamRotation;
 using ::android::hardware::camera::device::V3_2::StreamType;
 using ::android::hardware::camera::device::V3_2::DataspaceFlags;
+using ::android::hardware::camera::device::V3_2::CameraBlob;
+using ::android::hardware::camera::device::V3_2::CameraBlobId;
 using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
 using ::android::hardware::camera::device::V3_4::ICameraDeviceSession;
 using ::android::hardware::camera::common::V1_0::Status;
 using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::common::V1_0::helper::ExifUtils;
 using ::android::hardware::graphics::common::V1_0::BufferUsage;
 using ::android::hardware::graphics::common::V1_0::Dataspace;
 using ::android::hardware::graphics::common::V1_0::PixelFormat;
@@ -272,13 +276,19 @@
             hidl_vec<CaptureResult> &results, bool tryWriteFmq);
     static void freeReleaseFences(hidl_vec<CaptureResult>&);
 
+    Size getMaxJpegResolution() const;
+    Size getMaxThumbResolution() const;
+
+    ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
+
     class OutputThread : public android::Thread {
     public:
         OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType);
         ~OutputThread();
 
         Status allocateIntermediateBuffers(
-                const Size& v4lSize, const hidl_vec<Stream>& streams);
+                const Size& v4lSize, const Size& thumbSize,
+                const hidl_vec<Stream>& streams);
         Status submitRequest(const HalRequest&);
         void flush();
         virtual bool threadLoop() override;
@@ -296,12 +306,24 @@
 
         void waitForNextRequest(HalRequest* out);
         int cropAndScaleLocked(
-                sp<AllocatedFrame>& in, const HalStreamBuffer& halBuf,
+                sp<AllocatedFrame>& in, const Size& outSize,
+                YCbCrLayout* out);
+
+        int cropAndScaleThumbLocked(
+                sp<AllocatedFrame>& in, const Size& outSize,
                 YCbCrLayout* out);
 
         int formatConvertLocked(const YCbCrLayout& in, const YCbCrLayout& out,
                 Size sz, uint32_t format);
 
+        static int encodeJpegYU12(const Size &inSz,
+                const YCbCrLayout& inLayout, int jpegQuality,
+                const void *app1Buffer, size_t app1Size,
+                void *out, size_t maxOutSize,
+                size_t &actualCodeSize);
+
+        int createJpegLocked(HalStreamBuffer &halBuf, HalRequest &req);
+
         mutable std::mutex mLock;
         std::condition_variable mRequestCond;
         wp<ExternalCameraDeviceSession> mParent;
@@ -312,9 +334,11 @@
         // (Scale)-> mScaledYu12Frames
         // (Format convert) -> output gralloc frames
         sp<AllocatedFrame> mYu12Frame;
+        sp<AllocatedFrame> mYu12ThumbFrame;
         std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
         std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
         YCbCrLayout mYu12FrameLayout;
+        YCbCrLayout mYu12ThumbFrameLayout;
     };
 
     // Protect (most of) HIDL interface methods from synchronized-entering
@@ -359,6 +383,8 @@
     // Stream ID -> circulating buffers map
     std::map<int, CirculatingBuffers> mCirculatingBuffers;
 
+    bool mAfTrigger = false;
+
     static HandleImporter sHandleImporter;
 
     /* Beginning of members not changed after initialize() */
@@ -371,6 +397,9 @@
     Mutex mProcessCaptureResultLock;
 
     std::unordered_map<RequestTemplate, CameraMetadata> mDefaultRequests;
+
+    const Size mMaxThumbResolution;
+    const Size mMaxJpegResolution;
     /* End of members not changed after initialize() */
 
 private:
diff --git a/gnss/1.1/IGnss.hal b/gnss/1.1/IGnss.hal
index 0c3d876..096f251 100644
--- a/gnss/1.1/IGnss.hal
+++ b/gnss/1.1/IGnss.hal
@@ -17,6 +17,7 @@
 package android.hardware.gnss@1.1;
 
 import @1.0::IGnss;
+import @1.0::GnssLocation;
 
 import IGnssCallback;
 import IGnssConfiguration;
@@ -78,4 +79,16 @@
     * @return gnssMeasurementIface Handle to the IGnssMeasurement interface.
     */
     getExtensionGnssMeasurement_1_1() generates (IGnssMeasurement gnssMeasurementIface);
+
+    /**
+     * Injects current location from the best available location provider.
+     *
+     * Unlike injectLocation, this method may inject a recent GNSS location from the HAL
+     * implementation, if that is the best available location known to the framework.
+     *
+     * @param location Location information from the best available location provider.
+     *
+     * @return success Returns true if successful.
+     */
+    injectBestLocation(GnssLocation location) generates (bool success);
 };
\ No newline at end of file
diff --git a/gnss/1.1/IGnssCallback.hal b/gnss/1.1/IGnssCallback.hal
index 7a2849e..9fd71ae 100644
--- a/gnss/1.1/IGnssCallback.hal
+++ b/gnss/1.1/IGnssCallback.hal
@@ -35,4 +35,17 @@
      * @param name String providing the name of the GNSS HAL implementation
      */
     gnssNameCb(string name);
+
+    /**
+     * Callback for requesting Location.
+     *
+     * HAL implementation shall call this when it wants the framework to provide location to assist
+     * with GNSS HAL operation. For example, to assist with time to first fix, and/or error
+     * recovery, it may ask for a location that is independent from GNSS (e.g. from the "network"
+     * LocationProvier), or to provide a Device-Based-Hybrid location to supplement A-GPS/GNSS
+     * emergency call flows managed by the GNSS HAL.
+     *
+     * @param independentFromGnss True if requesting a location that is independent from GNSS.
+     */
+    gnssRequestLocationCb(bool independentFromGnss);
 };
\ No newline at end of file
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h
index a06db5d..6aab3cb 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.h
+++ b/gnss/1.1/vts/functional/gnss_hal_test.h
@@ -74,6 +74,9 @@
         }
         Return<void> gnssAcquireWakelockCb() override { return Void(); }
         Return<void> gnssReleaseWakelockCb() override { return Void(); }
+        Return<void> gnssRequestLocationCb(bool /* independentFromGnss */) override {
+            return Void();
+        }
         Return<void> gnssRequestTimeCb() override { return Void(); }
         // Actual (test) callback handlers
         Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
index c9e36a9..b4bad2c 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -23,6 +23,8 @@
 using android::hardware::hidl_vec;
 
 using android::hardware::gnss::V1_0::GnssConstellationType;
+using android::hardware::gnss::V1_0::GnssLocation;
+using android::hardware::gnss::V1_0::IGnssDebug;
 using android::hardware::gnss::V1_1::IGnssConfiguration;
 using android::hardware::gnss::V1_1::IGnssMeasurement;
 
@@ -363,4 +365,83 @@
     result = gnss_configuration_hal->setBlacklist(sources);
     ASSERT_TRUE(result.isOk());
     EXPECT_TRUE(result);
-}
\ No newline at end of file
+}
+
+/*
+ * InjectBestLocation
+ *
+ * Ensure successfully injecting a location.
+ */
+TEST_F(GnssHalTest, InjectBestLocation) {
+    GnssLocation gnssLocation = {.gnssLocationFlags = 0,  // set below
+                                 .latitudeDegrees = 43.0,
+                                 .longitudeDegrees = -180,
+                                 .altitudeMeters = 1000,
+                                 .speedMetersPerSec = 0,
+                                 .bearingDegrees = 0,
+                                 .horizontalAccuracyMeters = 0.1,
+                                 .verticalAccuracyMeters = 0.1,
+                                 .speedAccuracyMetersPerSecond = 0.1,
+                                 .bearingAccuracyDegrees = 0.1,
+                                 .timestamp = 1534567890123L};
+    gnssLocation.gnssLocationFlags |=
+        GnssLocationFlags::HAS_LAT_LONG | GnssLocationFlags::HAS_ALTITUDE |
+        GnssLocationFlags::HAS_SPEED | GnssLocationFlags::HAS_HORIZONTAL_ACCURACY |
+        GnssLocationFlags::HAS_VERTICAL_ACCURACY | GnssLocationFlags::HAS_SPEED_ACCURACY |
+        GnssLocationFlags::HAS_BEARING | GnssLocationFlags::HAS_BEARING_ACCURACY;
+
+    CheckLocation(gnssLocation, true);
+
+    auto result = gnss_hal_->injectBestLocation(gnssLocation);
+
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+}
+
+/*
+ * GnssDebugValuesSanityTest:
+ * Ensures that GnssDebug values make sense.
+ */
+TEST_F(GnssHalTest, GnssDebugValuesSanityTest) {
+    auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
+    ASSERT_TRUE(gnssDebug.isOk());
+    if (info_called_count_ > 0 && last_info_.yearOfHw >= 2017) {
+        sp<IGnssDebug> iGnssDebug = gnssDebug;
+        EXPECT_NE(iGnssDebug, nullptr);
+
+        IGnssDebug::DebugData data;
+        iGnssDebug->getDebugData(
+            [&data](const IGnssDebug::DebugData& debugData) { data = debugData; });
+
+        if (data.position.valid) {
+            EXPECT_GE(data.position.latitudeDegrees, -90);
+            EXPECT_LE(data.position.latitudeDegrees, 90);
+
+            EXPECT_GE(data.position.longitudeDegrees, -180);
+            EXPECT_LE(data.position.longitudeDegrees, 180);
+
+            EXPECT_GE(data.position.altitudeMeters, -1000);  // Dead Sea: -414m
+            EXPECT_LE(data.position.altitudeMeters, 20000);  // Mount Everest: 8850m
+
+            EXPECT_GE(data.position.speedMetersPerSec, 0);
+            EXPECT_LE(data.position.speedMetersPerSec, 600);
+
+            EXPECT_GE(data.position.bearingDegrees, -360);
+            EXPECT_LE(data.position.bearingDegrees, 360);
+
+            EXPECT_GE(data.position.horizontalAccuracyMeters, 0);
+            EXPECT_LE(data.position.horizontalAccuracyMeters, 20000000);
+
+            EXPECT_GE(data.position.verticalAccuracyMeters, 0);
+            EXPECT_LE(data.position.verticalAccuracyMeters, 20000);
+
+            EXPECT_GE(data.position.speedAccuracyMetersPerSecond, 0);
+            EXPECT_LE(data.position.speedAccuracyMetersPerSecond, 500);
+
+            EXPECT_GE(data.position.bearingAccuracyDegrees, 0);
+            EXPECT_LE(data.position.bearingAccuracyDegrees, 180);
+
+            EXPECT_GE(data.position.ageSeconds, 0);
+        }
+    }
+}
diff --git a/keymaster/4.0/support/Android.bp b/keymaster/4.0/support/Android.bp
index 6b8dcdc..ccd1b56 100644
--- a/keymaster/4.0/support/Android.bp
+++ b/keymaster/4.0/support/Android.bp
@@ -26,6 +26,8 @@
         "attestation_record.cpp",
         "authorization_set.cpp",
         "key_param_output.cpp",
+        "keymaster_utils.cpp",
+        "Keymaster.cpp",
         "Keymaster3.cpp",
         "Keymaster4.cpp",
     ],
diff --git a/keymaster/4.0/support/Keymaster.cpp b/keymaster/4.0/support/Keymaster.cpp
new file mode 100644
index 0000000..bf52c47
--- /dev/null
+++ b/keymaster/4.0/support/Keymaster.cpp
@@ -0,0 +1,90 @@
+/*
+ ** Copyright 2018, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include <keymasterV4_0/Keymaster.h>
+
+#include <android-base/logging.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <keymasterV4_0/Keymaster3.h>
+#include <keymasterV4_0/Keymaster4.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+using ::android::sp;
+using ::android::hidl::manager::V1_0::IServiceManager;
+
+template <typename Wrapper>
+std::vector<std::unique_ptr<Keymaster>> enumerateDevices(
+    const sp<IServiceManager>& serviceManager) {
+    std::vector<std::unique_ptr<Keymaster>> result;
+
+    bool foundDefault = false;
+    auto& descriptor = Wrapper::WrappedIKeymasterDevice::descriptor;
+    serviceManager->listByInterface(descriptor, [&](const hidl_vec<hidl_string>& names) {
+        for (auto& name : names) {
+            if (name == "default") foundDefault = true;
+            auto device = Wrapper::WrappedIKeymasterDevice::getService();
+            CHECK(device) << "Failed to get service for " << descriptor << " with interface name "
+                          << name;
+            result.push_back(std::unique_ptr<Keymaster>(new Wrapper(device, name)));
+        }
+    });
+
+    if (!foundDefault) {
+        // "default" wasn't provided by listByInterface.  Maybe there's a passthrough
+        // implementation.
+        auto device = Wrapper::WrappedIKeymasterDevice::getService("default");
+        if (device) result.push_back(std::unique_ptr<Keymaster>(new Wrapper(device, "default")));
+    }
+
+    return result;
+}
+
+std::vector<std::unique_ptr<Keymaster>> Keymaster::enumerateAvailableDevices() {
+    auto serviceManager = IServiceManager::getService();
+    CHECK(serviceManager) << "Could not retrieve ServiceManager";
+
+    auto km4s = enumerateDevices<Keymaster4>(serviceManager);
+    auto km3s = enumerateDevices<Keymaster3>(serviceManager);
+
+    auto result = std::move(km4s);
+    result.insert(result.end(), std::make_move_iterator(km3s.begin()),
+                  std::make_move_iterator(km3s.end()));
+
+    std::sort(result.begin(), result.end(),
+              [](auto& a, auto& b) { return a->halVersion() > b->halVersion(); });
+
+    size_t i = 1;
+    LOG(INFO) << "List of Keymaster HALs found:";
+    for (auto& hal : result) {
+        auto& version = hal->halVersion();
+        LOG(INFO) << "Keymaster HAL #" << i << ": " << version.keymasterName << " from "
+                  << version.authorName << " SecurityLevel: " << toString(version.securityLevel)
+                  << " HAL : " << hal->descriptor() << " instance " << hal->instanceName();
+    }
+
+    return result;
+}
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+};  // namespace android
diff --git a/keymaster/4.0/support/Keymaster3.cpp b/keymaster/4.0/support/Keymaster3.cpp
index 6dfe85b..b2cdbd9 100644
--- a/keymaster/4.0/support/Keymaster3.cpp
+++ b/keymaster/4.0/support/Keymaster3.cpp
@@ -18,7 +18,7 @@
 #include <keymasterV4_0/Keymaster3.h>
 
 #include <android-base/logging.h>
-#include <hardware/hw_auth_token.h>
+#include <keymasterV4_0/keymaster_utils.h>
 
 namespace android {
 namespace hardware {
@@ -82,35 +82,6 @@
     return std::copy(value_ptr, value_ptr + sizeof(value), dest);
 }
 
-constexpr size_t kHmacSize = 32;
-
-inline static hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token) {
-    static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
-                          sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
-                          sizeof(token.timestamp) + kHmacSize ==
-                      sizeof(hw_auth_token_t),
-                  "HardwareAuthToken content size does not match hw_auth_token_t size");
-
-    hidl_vec<uint8_t> result;
-    result.resize(sizeof(hw_auth_token_t));
-    auto pos = result.begin();
-    *pos++ = 0;  // Version byte
-    pos = copy_bytes_to_iterator(token.challenge, pos);
-    pos = copy_bytes_to_iterator(token.userId, pos);
-    pos = copy_bytes_to_iterator(token.authenticatorId, pos);
-    auto auth_type = htonl(static_cast<uint32_t>(token.authenticatorType));
-    pos = copy_bytes_to_iterator(auth_type, pos);
-    auto timestamp = htonq(token.timestamp);
-    pos = copy_bytes_to_iterator(timestamp, pos);
-    if (token.mac.size() != kHmacSize) {
-        std::fill(pos, pos + kHmacSize, 0);
-    } else {
-        std::copy(token.mac.begin(), token.mac.end(), pos);
-    }
-
-    return result;
-}
-
 hidl_vec<V3_0::KeyParameter> convertAndAddAuthToken(const hidl_vec<KeyParameter>& params,
                                                     const HardwareAuthToken& authToken) {
     hidl_vec<V3_0::KeyParameter> converted(params.size() + 1);
@@ -139,37 +110,32 @@
         [&](bool isSecure, bool supportsEllipticCurve, bool supportsSymmetricCryptography,
             bool supportsAttestation, bool supportsAllDigests, const hidl_string& keymasterName,
             const hidl_string& keymasterAuthorName) {
-            securityLevel_ =
-                isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE;
-            supportsEllipticCurve_ = supportsEllipticCurve;
+            version_ = {keymasterName, keymasterAuthorName, 0 /* major version, filled below */,
+                        isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE,
+                        supportsEllipticCurve};
             supportsSymmetricCryptography_ = supportsSymmetricCryptography;
             supportsAttestation_ = supportsAttestation;
             supportsAllDigests_ = supportsAllDigests;
-            keymasterName_ = keymasterName;
-            authorName_ = keymasterAuthorName;
         });
 
     CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware features";
 
-    if (securityLevel_ == SecurityLevel::SOFTWARE) {
-        majorVersion_ = 3;
+    if (version_.securityLevel == SecurityLevel::SOFTWARE) {
+        version_.majorVersion = 3;
     } else if (supportsAttestation_) {
-        majorVersion_ = 3;  // Could be 2, doesn't matter.
+        version_.majorVersion = 3;  // Could be 2, doesn't matter.
     } else if (supportsSymmetricCryptography_) {
-        majorVersion_ = 1;
+        version_.majorVersion = 1;
     } else {
-        majorVersion_ = 0;
+        version_.majorVersion = 0;
     }
 }
 
-Keymaster::VersionResult Keymaster3::halVersion() {
-    getVersionIfNeeded();
-    return {ErrorCode::OK, majorVersion_, securityLevel_, supportsEllipticCurve_};
-}
-
 Return<void> Keymaster3::getHardwareInfo(Keymaster3::getHardwareInfo_cb _hidl_cb) {
     getVersionIfNeeded();
-    _hidl_cb(securityLevel_, keymasterName_ + " (wrapped by keystore::Keymaster3)", authorName_);
+    _hidl_cb(version_.securityLevel,
+             std::string(version_.keymasterName) + " (wrapped by keystore::Keymaster3)",
+             version_.authorName);
     return Void();
 }
 
diff --git a/keymaster/4.0/support/Keymaster4.cpp b/keymaster/4.0/support/Keymaster4.cpp
index fdf78ae..cc3d656 100644
--- a/keymaster/4.0/support/Keymaster4.cpp
+++ b/keymaster/4.0/support/Keymaster4.cpp
@@ -28,19 +28,17 @@
 void Keymaster4::getVersionIfNeeded() {
     if (haveVersion_) return;
 
-    auto rc = dev_->getHardwareInfo([&](SecurityLevel securityLevel, auto...) {
-        securityLevel_ = securityLevel;
-        haveVersion_ = true;
-    });
+    auto rc =
+        dev_->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& keymasterName,
+                                  const hidl_string& authorName) {
+            version_ = {keymasterName, authorName, 4 /* major version */, securityLevel,
+                        true /* supportsEc */};
+            haveVersion_ = true;
+        });
 
     CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware info";
 }
 
-Keymaster::VersionResult Keymaster4::halVersion() {
-    getVersionIfNeeded();
-    return {ErrorCode::OK, halMajorVersion(), securityLevel_, true};
-}
-
 }  // namespace support
 }  // namespace V4_0
 }  // namespace keymaster
diff --git a/keymaster/4.0/support/authorization_set.cpp b/keymaster/4.0/support/authorization_set.cpp
index 81cf365..bf77420 100644
--- a/keymaster/4.0/support/authorization_set.cpp
+++ b/keymaster/4.0/support/authorization_set.cpp
@@ -503,6 +503,18 @@
     return Authorization(TAG_BLOCK_MODE, BlockMode::ECB);
 }
 
+AuthorizationSetBuilder& AuthorizationSetBuilder::GcmModeMinMacLen(uint32_t minMacLength) {
+    return BlockMode(BlockMode::GCM)
+        .Padding(PaddingMode::NONE)
+        .Authorization(TAG_MIN_MAC_LENGTH, minMacLength);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::GcmModeMacLen(uint32_t macLength) {
+    return BlockMode(BlockMode::GCM)
+        .Padding(PaddingMode::NONE)
+        .Authorization(TAG_MAC_LENGTH, macLength);
+}
+
 AuthorizationSetBuilder& AuthorizationSetBuilder::BlockMode(
     std::initializer_list<V4_0::BlockMode> blockModes) {
     for (auto mode : blockModes) {
@@ -519,6 +531,14 @@
     return *this;
 }
 
+AuthorizationSetBuilder& AuthorizationSetBuilder::Padding(
+    std::initializer_list<V4_0::PaddingMode> paddingModes) {
+    for (auto paddingMode : paddingModes) {
+        push_back(TAG_PADDING, paddingMode);
+    }
+    return *this;
+}
+
 }  // namespace V4_0
 }  // namespace keymaster
 }  // namespace hardware
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
index 2686fcd..f9efd51 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
@@ -37,16 +37,37 @@
  */
 class Keymaster : public IKeymasterDevice {
    public:
+    Keymaster(const hidl_string& descriptor, const hidl_string& instanceName)
+        : descriptor_(descriptor), instanceName_(instanceName) {}
     virtual ~Keymaster() {}
 
     struct VersionResult {
-        ErrorCode error;
+        hidl_string keymasterName;
+        hidl_string authorName;
         uint8_t majorVersion;
         SecurityLevel securityLevel;
         bool supportsEc;
+
+        bool operator>(const VersionResult& other) const {
+            auto lhs = std::tie(securityLevel, majorVersion, supportsEc);
+            auto rhs = std::tie(other.securityLevel, other.majorVersion, other.supportsEc);
+            return lhs > rhs;
+        }
     };
 
-    virtual VersionResult halVersion() = 0;
+    virtual const VersionResult& halVersion() = 0;
+    const hidl_string& descriptor() { return descriptor_; }
+    const hidl_string& instanceName() { return instanceName_; }
+
+    /**
+     * Returns all available Keymaster3 and Keymaster4 instances, in order of most secure to least
+     * secure (as defined by VersionResult::operator<).
+     */
+    static std::vector<std::unique_ptr<Keymaster>> enumerateAvailableDevices();
+
+   private:
+    hidl_string descriptor_;
+    hidl_string instanceName_;
 };
 
 }  // namespace support
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
index 4054620..2bb77ca 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
@@ -40,9 +40,15 @@
 class Keymaster3 : public Keymaster {
    public:
     using WrappedIKeymasterDevice = IKeymaster3Device;
-    Keymaster3(sp<IKeymaster3Device> km3_dev) : km3_dev_(km3_dev), haveVersion_(false) {}
+    Keymaster3(sp<IKeymaster3Device> km3_dev, const hidl_string& instanceName)
+        : Keymaster(IKeymaster3Device::descriptor, instanceName),
+          km3_dev_(km3_dev),
+          haveVersion_(false) {}
 
-    VersionResult halVersion() override;
+    const VersionResult& halVersion() override {
+        getVersionIfNeeded();
+        return version_;
+    }
 
     Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb);
 
@@ -114,14 +120,10 @@
     sp<IKeymaster3Device> km3_dev_;
 
     bool haveVersion_;
-    uint8_t majorVersion_;
-    SecurityLevel securityLevel_;
-    bool supportsEllipticCurve_;
+    VersionResult version_;
     bool supportsSymmetricCryptography_;
     bool supportsAttestation_;
     bool supportsAllDigests_;
-    std::string keymasterName_;
-    std::string authorName_;
 };
 
 }  // namespace support
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
index 86ef4f8..96afb13 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
@@ -32,11 +32,15 @@
 class Keymaster4 : public Keymaster {
    public:
     using WrappedIKeymasterDevice = IKeymaster4Device;
-    Keymaster4(sp<IKeymasterDevice> km4_dev) : haveVersion_(false), dev_(km4_dev) {}
+    Keymaster4(sp<IKeymasterDevice> km4_dev, const hidl_string& instanceName)
+        : Keymaster(IKeymaster4Device::descriptor, instanceName),
+          haveVersion_(false),
+          dev_(km4_dev) {}
 
-    uint8_t halMajorVersion() { return 4; }
-
-    VersionResult halVersion() override;
+    const VersionResult& halVersion() override {
+        getVersionIfNeeded();
+        return version_;
+    }
 
     Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb) override {
         return dev_->getHardwareInfo(_hidl_cb);
@@ -143,7 +147,7 @@
     void getVersionIfNeeded();
 
     bool haveVersion_;
-    SecurityLevel securityLevel_;
+    VersionResult version_;
     sp<IKeymaster4Device> dev_;
 };
 
diff --git a/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
index 09a06fe..6c7fd35 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
@@ -270,11 +270,16 @@
 
     AuthorizationSetBuilder& SigningKey();
     AuthorizationSetBuilder& EncryptionKey();
+
     AuthorizationSetBuilder& NoDigestOrPadding();
+
     AuthorizationSetBuilder& EcbMode();
+    AuthorizationSetBuilder& GcmModeMinMacLen(uint32_t minMacLength);
+    AuthorizationSetBuilder& GcmModeMacLen(uint32_t macLength);
 
     AuthorizationSetBuilder& BlockMode(std::initializer_list<BlockMode> blockModes);
     AuthorizationSetBuilder& Digest(std::initializer_list<Digest> digests);
+    AuthorizationSetBuilder& Padding(std::initializer_list<PaddingMode> paddings);
 
     template <typename... T>
     AuthorizationSetBuilder& BlockMode(T&&... a) {
@@ -288,10 +293,6 @@
     AuthorizationSetBuilder& Padding(T&&... a) {
         return Padding({std::forward<T>(a)...});
     }
-
-    AuthorizationSetBuilder& Padding(PaddingMode padding) {
-        return Authorization(TAG_PADDING, padding);
-    }
 };
 
 }  // namespace V4_0
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
index 9d6501b..ce213bc 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
@@ -142,24 +142,28 @@
 DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT);
 DECLARE_TYPED_TAG(TRUSTED_CONFIRMATION_REQUIRED);
 DECLARE_TYPED_TAG(UNIQUE_ID);
+DECLARE_TYPED_TAG(UNLOCKED_DEVICE_REQUIRED);
 DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME);
 DECLARE_TYPED_TAG(USER_AUTH_TYPE);
+DECLARE_TYPED_TAG(USER_ID);
 DECLARE_TYPED_TAG(USER_SECURE_ID);
 
 template <typename... Elems>
 struct MetaList {};
 
-using all_tags_t = MetaList<
-    TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t,
-    TAG_RSA_PUBLIC_EXPONENT_t, TAG_INCLUDE_UNIQUE_ID_t, TAG_ACTIVE_DATETIME_t,
-    TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t, TAG_MIN_SECONDS_BETWEEN_OPS_t,
-    TAG_MAX_USES_PER_BOOT_t, TAG_USER_SECURE_ID_t, TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t,
-    TAG_ALLOW_WHILE_ON_BODY_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t,
-    TAG_CREATION_DATETIME_t, TAG_ROLLBACK_RESISTANCE_t, TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t,
-    TAG_NONCE_t, TAG_BOOTLOADER_ONLY_t, TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t,
-    TAG_ATTESTATION_CHALLENGE_t, TAG_ATTESTATION_APPLICATION_ID_t, TAG_RESET_SINCE_ID_ROTATION_t,
-    TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, TAG_DIGEST_t, TAG_PADDING_t,
-    TAG_BLOB_USAGE_REQUIREMENTS_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_EC_CURVE_t>;
+using all_tags_t =
+    MetaList<TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t,
+             TAG_MIN_MAC_LENGTH_t, TAG_RSA_PUBLIC_EXPONENT_t, TAG_INCLUDE_UNIQUE_ID_t,
+             TAG_ACTIVE_DATETIME_t, TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t,
+             TAG_MIN_SECONDS_BETWEEN_OPS_t, TAG_MAX_USES_PER_BOOT_t, TAG_USER_ID_t,
+             TAG_USER_SECURE_ID_t, TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t,
+             TAG_ALLOW_WHILE_ON_BODY_t, TAG_UNLOCKED_DEVICE_REQUIRED_t, TAG_APPLICATION_ID_t,
+             TAG_APPLICATION_DATA_t, TAG_CREATION_DATETIME_t, TAG_ROLLBACK_RESISTANCE_t,
+             TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t, TAG_BOOTLOADER_ONLY_t,
+             TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t, TAG_ATTESTATION_CHALLENGE_t,
+             TAG_ATTESTATION_APPLICATION_ID_t, TAG_RESET_SINCE_ID_ROTATION_t, TAG_PURPOSE_t,
+             TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, TAG_DIGEST_t, TAG_PADDING_t,
+             TAG_BLOB_USAGE_REQUIREMENTS_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_EC_CURVE_t>;
 
 template <typename TypedTagType>
 struct TypedTag2ValueType;
@@ -343,6 +347,7 @@
         case Tag::BOOTLOADER_ONLY:
         case Tag::NO_AUTH_REQUIRED:
         case Tag::ALLOW_WHILE_ON_BODY:
+        case Tag::UNLOCKED_DEVICE_REQUIRED:
         case Tag::ROLLBACK_RESISTANCE:
         case Tag::RESET_SINCE_ID_ROTATION:
         case Tag::TRUSTED_CONFIRMATION_REQUIRED:
@@ -357,6 +362,7 @@
         case Tag::OS_VERSION:
         case Tag::OS_PATCHLEVEL:
         case Tag::MAC_LENGTH:
+        case Tag::USER_ID:
         case Tag::AUTH_TIMEOUT:
         case Tag::VENDOR_PATCHLEVEL:
         case Tag::BOOT_PATCHLEVEL:
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
new file mode 100644
index 0000000..1c1b000
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_UTILS_H_
+#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_UTILS_H_
+
+#include <android/hardware/keymaster/4.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+inline static hidl_vec<uint8_t> blob2hidlVec(const uint8_t* data, const size_t length,
+                                             bool inPlace = true) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(const_cast<unsigned char*>(data), length, !inPlace);
+    return result;
+}
+
+inline static hidl_vec<uint8_t> blob2hidlVec(const std::string& value, bool inPlace = true) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(value.data())),
+                         static_cast<size_t>(value.size()), !inPlace);
+    return result;
+}
+
+inline static hidl_vec<uint8_t> blob2hidlVec(const std::vector<uint8_t>& blob,
+                                             bool inPlace = true) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(const_cast<uint8_t*>(blob.data()), static_cast<size_t>(blob.size()),
+                         !inPlace);
+    return result;
+}
+
+HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer);
+hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token);
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_UTILS_H_
diff --git a/keymaster/4.0/support/keymaster_utils.cpp b/keymaster/4.0/support/keymaster_utils.cpp
new file mode 100644
index 0000000..bc610aa
--- /dev/null
+++ b/keymaster/4.0/support/keymaster_utils.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hardware/hw_auth_token.h>
+#include <keymasterV4_0/keymaster_utils.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+template <typename T, typename InIter>
+inline static InIter copy_bytes_from_iterator(T* value, InIter src) {
+    uint8_t* value_ptr = reinterpret_cast<uint8_t*>(value);
+    std::copy(src, src + sizeof(T), value_ptr);
+    return src + sizeof(T);
+}
+
+template <typename T, typename OutIter>
+inline static OutIter copy_bytes_to_iterator(const T& value, OutIter dest) {
+    const uint8_t* value_ptr = reinterpret_cast<const uint8_t*>(&value);
+    return std::copy(value_ptr, value_ptr + sizeof(value), dest);
+}
+
+constexpr size_t kHmacSize = 32;
+
+hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token) {
+    static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
+                          sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
+                          sizeof(token.timestamp) + kHmacSize ==
+                      sizeof(hw_auth_token_t),
+                  "HardwareAuthToken content size does not match hw_auth_token_t size");
+
+    hidl_vec<uint8_t> result;
+    result.resize(sizeof(hw_auth_token_t));
+    auto pos = result.begin();
+    *pos++ = 0;  // Version byte
+    pos = copy_bytes_to_iterator(token.challenge, pos);
+    pos = copy_bytes_to_iterator(token.userId, pos);
+    pos = copy_bytes_to_iterator(token.authenticatorId, pos);
+    auto auth_type = htonl(static_cast<uint32_t>(token.authenticatorType));
+    pos = copy_bytes_to_iterator(auth_type, pos);
+    auto timestamp = htonq(token.timestamp);
+    pos = copy_bytes_to_iterator(timestamp, pos);
+    if (token.mac.size() != kHmacSize) {
+        std::fill(pos, pos + kHmacSize, 0);
+    } else {
+        std::copy(token.mac.begin(), token.mac.end(), pos);
+    }
+
+    return result;
+}
+
+HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer) {
+    HardwareAuthToken token;
+    static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
+                          sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
+                          sizeof(token.timestamp) + kHmacSize ==
+                      sizeof(hw_auth_token_t),
+                  "HardwareAuthToken content size does not match hw_auth_token_t size");
+
+    if (buffer.size() != sizeof(hw_auth_token_t)) return {};
+
+    auto pos = buffer.begin();
+    ++pos;  // skip first byte
+    pos = copy_bytes_from_iterator(&token.challenge, pos);
+    pos = copy_bytes_from_iterator(&token.userId, pos);
+    pos = copy_bytes_from_iterator(&token.authenticatorId, pos);
+    pos = copy_bytes_from_iterator(&token.authenticatorType, pos);
+    token.authenticatorType = static_cast<HardwareAuthenticatorType>(
+        ntohl(static_cast<uint32_t>(token.authenticatorType)));
+    pos = copy_bytes_from_iterator(&token.timestamp, pos);
+    token.timestamp = ntohq(token.timestamp);
+    token.mac.resize(kHmacSize);
+    std::copy(pos, pos + kHmacSize, token.mac.data());
+
+    return token;
+}
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/4.0/types.hal b/keymaster/4.0/types.hal
index 91ec9bf..47fd1ed 100644
--- a/keymaster/4.0/types.hal
+++ b/keymaster/4.0/types.hal
@@ -118,7 +118,8 @@
                                                        * boot. */
 
     /* User authentication */
-    // 500-501 reserved
+    // 500 reserved
+    USER_ID = TagType:UINT | 501,             /* Android ID of authorized user or authenticator(s), */
     USER_SECURE_ID = TagType:ULONG_REP | 502, /* Secure ID of authorized user or authenticator(s).
                                                * Disallowed if NO_AUTH_REQUIRED is present. */
     NO_AUTH_REQUIRED = TagType:BOOL | 503,    /* If key is usable without authentication. */
@@ -191,6 +192,9 @@
      * match the data described in the token, keymaster must return NO_USER_CONFIRMATION. */
     TRUSTED_CONFIRMATION_REQUIRED = TagType:BOOL | 508,
 
+    UNLOCKED_DEVICE_REQUIRED = TagType:BOOL | 509, /* Require the device screen to be unlocked if
+                                                    * the key is used. */
+
     /* Application access control */
     APPLICATION_ID = TagType:BYTES | 601, /* Byte string identifying the authorized application. */
 
@@ -471,6 +475,7 @@
     PROOF_OF_PRESENCE_REQUIRED = -69,
     CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = -70,
     NO_USER_CONFIRMATION = -71,
+    DEVICE_LOCKED = -72,
 
     UNIMPLEMENTED = -100,
     VERSION_MISMATCH = -101,
diff --git a/radio/1.2/IRadio.hal b/radio/1.2/IRadio.hal
index babe86f..67ce56c 100644
--- a/radio/1.2/IRadio.hal
+++ b/radio/1.2/IRadio.hal
@@ -18,6 +18,8 @@
 
 import @1.1::IRadio;
 import @1.1::RadioAccessNetworks;
+import @1.0::DataProfileInfo;
+import @1.0::RadioTechnology;
 
 /**
  * This interface is used by telephony and telecom to talk to cellular radio.
@@ -106,4 +108,67 @@
     oneway setLinkCapacityReportingCriteria(int32_t serial, int32_t hysteresisMs,
             int32_t hysteresisDlKbps, int32_t hysteresisUlKbps, vec<int32_t> thresholdsDownlinkKbps,
             vec<int32_t> thresholdsUplinkKbps, RadioAccessNetworks ran);
+
+    /**
+     * Setup a packet data connection. If DataCallResponse.status returns DataCallFailCause:NONE,
+     * the data connection must be added to data calls and a unsolDataCallListChanged() must be
+     * sent. The call remains until removed by subsequent unsolDataCallIstChanged(). It may be
+     * lost due to many factors, including deactivateDataCall() being issued, the radio powered
+     * off, reception lost or even transient factors like congestion. This data call list is
+     * returned by getDataCallList() and dataCallListChanged().
+     *
+     * The Radio is expected to:
+     *   - Create one data call context.
+     *   - Create and configure a dedicated interface for the context.
+     *   - The interface must be point to point.
+     *   - The interface is configured with one or more addresses and is capable of sending and
+     *     receiving packets. The prefix length of the addresses must be /32 for IPv4 and /128
+     *     for IPv6.
+     *   - Must not modify routing configuration related to this interface; routing management is
+     *     exclusively within the purview of the Android OS.
+     *   - Support simultaneous data call contexts up to DataRegStateResult.maxDataCalls specified
+     *     in the response of getDataRegistrationState.
+     *
+     * @param serial Serial number of request.
+     * @param accessNetwork The access network to setup the data call. If the data connection cannot
+     *     be established on the specified access network, the setup request must be failed.
+     * @param dataProfileInfo Data profile info.
+     * @param modemCognitive Indicates that the requested profile has previously been provided via
+     *     setDataProfile().
+     * @param roamingAllowed Indicates whether or not data roaming is allowed by the user.
+     * @param isRoaming Indicates whether or not the framework has requested this setupDataCall for
+     *     a roaming network. The 'protocol' parameter in the old RIL API must be filled
+     *     accordingly based on the roaming condition. Note this is for backward compatibility with
+     *     the old radio modem. The modem must not use this param for any other reason.
+     * @param reason The request reason. Must be DataRequestReason.NORMAL or
+     *     DataRequestReason.HANDOVER.
+     * @param addresses If the reason is DataRequestReason.HANDOVER, this indicates the list of link
+     *     addresses of the existing data connection. The format is IP address with optional "/"
+     *     prefix length (The format is defined in RFC-4291 section 2.3). For example, "192.0.1.3",
+     *     "192.0.1.11/16", or "2001:db8::1/64". Typically one IPv4 or one IPv6 or one of each. If
+     *     the prefix length is absent, then the addresses are assumed to be point to point with
+     *     IPv4 with prefix length 32 or IPv6 with prefix length 128. This parameter must be ignored
+     *     unless reason is DataRequestReason.HANDOVER.
+     * @param dnses If the reason is DataRequestReason.HANDOVER, this indicates the list of DNS
+     *     addresses of the existing data connection. The format is defined in RFC-4291 section
+     *     2.2. For example, "192.0.1.3" or "2001:db8::1". This parameter must be ignored unless
+     *     reason is DataRequestReason.HANDOVER.
+     *
+     * Response function is IRadioResponse.setupDataCallResponse()
+     */
+    oneway setupDataCall_1_2(int32_t serial, AccessNetwork accessNetwork,
+            DataProfileInfo dataProfileInfo, bool modemCognitive, bool roamingAllowed,
+            bool isRoaming, DataRequestReason reason, vec<string> addresses, vec<string> dnses);
+
+    /**
+     * Deactivate packet data connection and remove from the data call list. An
+     * unsolDataCallListChanged() must be sent when data connection is deactivated.
+     *
+     * @param serial Serial number of request.
+     * @param cid Data call id.
+     * @param reason The request reason. Must be normal, handover, or shutdown.
+     *
+     * Response function is IRadioResponse.deactivateDataCallResponse()
+     */
+    oneway deactivateDataCall_1_2(int32_t serial, int32_t cid, DataRequestReason reason);
 };
diff --git a/radio/1.2/types.hal b/radio/1.2/types.hal
index 4515237..f2f0b69 100644
--- a/radio/1.2/types.hal
+++ b/radio/1.2/types.hal
@@ -335,3 +335,32 @@
      */
     int32_t cellBandwidthDownlink;
 };
+
+enum AccessNetwork : int32_t {
+    /** GSM EDGE Radio Access Network */
+    GERAN       = 1,
+    /** Universal Terrestrial Radio Access Network */
+    UTRAN       = 2,
+    /** Evolved Universal Terrestrial Radio Access Network */
+    EUTRAN      = 3,
+    /** CDMA 2000 network */
+    CDMA2000    = 4,
+    /** Interworking Wireless LAN */
+    IWLAN       = 5
+};
+
+enum DataRequestReason : int32_t {
+    /**
+     * The reason of the data request is normal
+     */
+    NORMAL    = 0x01,
+    /**
+     * The reason of the data request is device shutdown
+     */
+    SHUTDOWN  = 0x02,
+    /**
+     * The reason of the data request is IWLAN data handover to another transport
+     * (e.g. from cellular to wifi or vise versa)
+     */
+    HANDOVER  = 0x03,
+};
diff --git a/wifi/1.2/IWifiChip.hal b/wifi/1.2/IWifiChip.hal
index d336a33..480c5a2 100644
--- a/wifi/1.2/IWifiChip.hal
+++ b/wifi/1.2/IWifiChip.hal
@@ -27,6 +27,50 @@
  */
 interface IWifiChip extends @1.1::IWifiChip {
     /**
+     * Capabilities exposed by this chip.
+     */
+    enum ChipCapabilityMask : @1.1::IWifiChip.ChipCapabilityMask {
+        /**
+         * Set/Reset Tx Power limits.
+         */
+         USE_BODY_HEAD_SAR = 1 << 11
+    };
+
+    /**
+     * List of preset wifi radio TX power levels for different scenarios.
+     * The actual power values (typically varies based on the channel,
+     * 802.11 connection type, number of MIMO streams, etc) for each scenario
+     * is defined by the OEM as a BDF file since it varies for each wifi chip
+     * vendor and device.
+     */
+    enum TxPowerScenario : @1.1::IWifiChip.TxPowerScenario {
+        ON_HEAD_CELL_OFF = 1,
+        ON_HEAD_CELL_ON  = 2,
+        ON_BODY_CELL_OFF = 3,
+        ON_BODY_CELL_ON  = 4
+    };
+
+    /**
+     * API to select one of the preset TX power scenarios.
+     *
+     * The framework must invoke this method with the appropriate scenario to let
+     * the wifi chip change it's transmitting power levels.
+     * OEM's should define various power profiles for each of the scenarios
+     * above (defined in |TxPowerScenario|) in a vendor extension.
+     *
+     * @param scenario One of the preselected scenarios defined in
+     *        |TxPowerScenario|.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.NOT_AVAILABLE|,
+     *         |WifiStatusCode.UNKNOWN|
+     */
+    selectTxPowerScenario_1_2(TxPowerScenario scenario) generates (WifiStatus status);
+
+    /**
      * Requests notifications of significant events on this chip. Multiple calls
      * to this must register multiple callbacks each of which must receive all
      * events.
diff --git a/wifi/1.2/default/hidl_struct_util.cpp b/wifi/1.2/default/hidl_struct_util.cpp
index b1c609e..2e3e0ab 100644
--- a/wifi/1.2/default/hidl_struct_util.cpp
+++ b/wifi/1.2/default/hidl_struct_util.cpp
@@ -66,12 +66,14 @@
     return {};
 }
 
-V1_1::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
+IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
     uint32_t feature) {
-    using HidlChipCaps = V1_1::IWifiChip::ChipCapabilityMask;
+    using HidlChipCaps = IWifiChip::ChipCapabilityMask;
     switch (feature) {
         case WIFI_FEATURE_SET_TX_POWER_LIMIT:
             return HidlChipCaps::SET_TX_POWER_LIMIT;
+        case WIFI_FEATURE_USE_BODY_HEAD_SAR:
+            return HidlChipCaps::USE_BODY_HEAD_SAR;
         case WIFI_FEATURE_D2D_RTT:
             return HidlChipCaps::D2D_RTT;
         case WIFI_FEATURE_D2AP_RTT:
@@ -135,6 +137,7 @@
         }
     }
     for (const auto feature : {WIFI_FEATURE_SET_TX_POWER_LIMIT,
+                               WIFI_FEATURE_USE_BODY_HEAD_SAR,
                                WIFI_FEATURE_D2D_RTT, WIFI_FEATURE_D2AP_RTT}) {
         if (feature & legacy_feature_set) {
             *hidl_caps |= convertLegacyFeatureToHidlChipCapability(feature);
@@ -260,12 +263,32 @@
 legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
     V1_1::IWifiChip::TxPowerScenario hidl_scenario) {
     switch (hidl_scenario) {
-        case V1_1::IWifiChip::TxPowerScenario::VOICE_CALL:
+        // This is the only supported scenario for V1_1
+      case V1_1::IWifiChip::TxPowerScenario::VOICE_CALL:
             return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
     };
     CHECK(false);
 }
 
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
+    IWifiChip::TxPowerScenario hidl_scenario) {
+    switch (hidl_scenario) {
+        // This is the only supported scenario for V1_1
+        case IWifiChip::TxPowerScenario::VOICE_CALL:
+            return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
+        // Those are the supported scenarios for V1_2
+        case IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
+        case IWifiChip::TxPowerScenario::ON_HEAD_CELL_ON:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
+        case IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
+        case IWifiChip::TxPowerScenario::ON_BODY_CELL_ON:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
+    };
+    CHECK(false);
+}
+
 bool convertLegacyWifiMacInfoToHidl(
     const legacy_hal::WifiMacInfo& legacy_mac_info,
     IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
diff --git a/wifi/1.2/default/hidl_struct_util.h b/wifi/1.2/default/hidl_struct_util.h
index ce4bb81..3c789c0 100644
--- a/wifi/1.2/default/hidl_struct_util.h
+++ b/wifi/1.2/default/hidl_struct_util.h
@@ -21,7 +21,7 @@
 
 #include <android/hardware/wifi/1.0/IWifiChip.h>
 #include <android/hardware/wifi/1.0/types.h>
-#include <android/hardware/wifi/1.1/IWifiChip.h>
+#include <android/hardware/wifi/1.2/IWifiChip.h>
 #include <android/hardware/wifi/1.2/IWifiChipEventCallback.h>
 #include <android/hardware/wifi/1.2/types.h>
 
@@ -56,6 +56,8 @@
     WifiDebugHostWakeReasonStats* hidl_stats);
 legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
     V1_1::IWifiChip::TxPowerScenario hidl_scenario);
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
+    IWifiChip::TxPowerScenario hidl_scenario);
 bool convertLegacyWifiMacInfosToHidl(
     const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
     std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos);
diff --git a/wifi/1.2/default/wifi_chip.cpp b/wifi/1.2/default/wifi_chip.cpp
index 38301e9..05ea638 100644
--- a/wifi/1.2/default/wifi_chip.cpp
+++ b/wifi/1.2/default/wifi_chip.cpp
@@ -507,7 +507,7 @@
 }
 
 Return<void> WifiChip::selectTxPowerScenario(
-    TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) {
+    V1_1::IWifiChip::TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
                            &WifiChip::selectTxPowerScenarioInternal,
                            hidl_status_cb, scenario);
@@ -528,6 +528,12 @@
                            hidl_status_cb, event_callback);
 }
 
+Return<void> WifiChip::selectTxPowerScenario_1_2(
+        TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+            &WifiChip::selectTxPowerScenarioInternal_1_2, hidl_status_cb, scenario);
+}
+
 Return<void> WifiChip::debug(const hidl_handle& handle,
                              const hidl_vec<hidl_string>&) {
     if (handle != nullptr && handle->numFds >= 1) {
@@ -990,7 +996,8 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
-WifiStatus WifiChip::selectTxPowerScenarioInternal(TxPowerScenario scenario) {
+WifiStatus WifiChip::selectTxPowerScenarioInternal(
+        V1_1::IWifiChip::TxPowerScenario scenario) {
     auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
         getWlan0IfaceName(),
         hidl_struct_util::convertHidlTxPowerScenarioToLegacy(scenario));
@@ -1011,6 +1018,13 @@
     return createWifiStatus(WifiStatusCode::SUCCESS);
 }
 
+WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario) {
+    auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
+        getWlan0IfaceName(),
+        hidl_struct_util::convertHidlTxPowerScenarioToLegacy_1_2(scenario));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
 WifiStatus WifiChip::handleChipConfiguration(
     /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
     ChipModeId mode_id) {
diff --git a/wifi/1.2/default/wifi_chip.h b/wifi/1.2/default/wifi_chip.h
index 24a5486..ada9458 100644
--- a/wifi/1.2/default/wifi_chip.h
+++ b/wifi/1.2/default/wifi_chip.h
@@ -132,16 +132,18 @@
     Return<void> enableDebugErrorAlerts(
         bool enable, enableDebugErrorAlerts_cb hidl_status_cb) override;
     Return<void> selectTxPowerScenario(
-        TxPowerScenario scenario,
+        V1_1::IWifiChip::TxPowerScenario scenario,
         selectTxPowerScenario_cb hidl_status_cb) override;
     Return<void> resetTxPowerScenario(
         resetTxPowerScenario_cb hidl_status_cb) override;
-    Return<void> debug(const hidl_handle& handle,
-                       const hidl_vec<hidl_string>& options) override;
     Return<void> registerEventCallback_1_2(
         const sp<IWifiChipEventCallback>& event_callback,
         registerEventCallback_1_2_cb hidl_status_cb) override;
-
+    Return<void> selectTxPowerScenario_1_2(
+        TxPowerScenario scenario,
+        selectTxPowerScenario_cb hidl_status_cb) override;
+    Return<void> debug(const hidl_handle& handle,
+                       const hidl_vec<hidl_string>& options) override;
    private:
     void invalidateAndRemoveAllIfaces();
 
@@ -193,11 +195,11 @@
     std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
     getDebugHostWakeReasonStatsInternal();
     WifiStatus enableDebugErrorAlertsInternal(bool enable);
-    WifiStatus selectTxPowerScenarioInternal(TxPowerScenario scenario);
+    WifiStatus selectTxPowerScenarioInternal(V1_1::IWifiChip::TxPowerScenario scenario);
     WifiStatus resetTxPowerScenarioInternal();
     WifiStatus registerEventCallbackInternal_1_2(
         const sp<IWifiChipEventCallback>& event_callback);
-
+    WifiStatus selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario);
     WifiStatus handleChipConfiguration(
         std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
     WifiStatus registerDebugRingBufferCallback();
diff --git a/wifi/supplicant/1.1/Android.bp b/wifi/supplicant/1.1/Android.bp
index c8c8a32..fafd6ad 100644
--- a/wifi/supplicant/1.1/Android.bp
+++ b/wifi/supplicant/1.1/Android.bp
@@ -8,6 +8,7 @@
     },
     srcs: [
         "ISupplicant.hal",
+        "ISupplicantStaNetwork.hal",
     ],
     interfaces: [
         "android.hardware.wifi.supplicant@1.0",
diff --git a/wifi/supplicant/1.1/ISupplicantStaNetwork.hal b/wifi/supplicant/1.1/ISupplicantStaNetwork.hal
new file mode 100644
index 0000000..186fe75
--- /dev/null
+++ b/wifi/supplicant/1.1/ISupplicantStaNetwork.hal
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant@1.1;
+
+import @1.0::ISupplicantNetwork;
+import @1.0::ISupplicantStaNetworkCallback;
+import @1.0::SupplicantStatus;
+import @1.0::ISupplicantStaNetwork;
+
+/**
+ * Interface exposed by the supplicant for each station mode network
+ * configuration it controls.
+ */
+interface ISupplicantStaNetwork extends @1.0::ISupplicantStaNetwork {
+    /**
+     * EAP IMSI Identity to be used for authentication to EAP SIM networks.
+     * The identity must be derived from the IMSI retrieved from the SIM card.
+     *
+     * See RFC4186 & RFC4187 & RFC5448 for EAP SIM protocols.
+     *
+     * Identity string is built from IMSI. Format is:
+     *       eapPrefix | IMSI | '@' | realm
+     * where:
+     * - "|" denotes concatenation
+     * - realm is the 3GPP network domain name derived from the given
+     *   MCC/MNC according to the 3GGP spec(TS23.003)
+     *
+     * eapPrefix value:
+     * '0' - EAP-AKA Identity
+     * '1' - EAP-SIM Identity
+     * '6' - EAP-AKA-PRIME Identity
+     */
+    typedef vec<uint8_t> EapSimIdentity;
+
+    /**
+     * Encrypted EAP IMSI Identity to be used for authentication to EAP SIM
+     * networks which supports encrypted IMSI.
+     * The identity must be derived from the IMSI retrieved from the SIM card.
+     * This identity is then encrypted using the public key of the carrier.
+     *
+     * See RFC4186 & RFC4187 & RFC5448 for EAP SIM protocols.
+     * See section 7.1 of RFC 2437 for RSA-OAEP encryption scheme.
+     *
+     * Identity string is built from encrypted IMSI. Format is:
+     *       '\0' | Base64{RSA-OAEP-SHA-256(eapPrefix | IMSI)}
+     *       | '@' | realm | {',' Key Identifier}
+     * where:
+     * - "|" denotes concatenation
+     * - "{}" denotes an optional value
+     * - realm is the 3GPP network domain name derived from the given
+     *   MCC/MNC according to the 3GGP spec(TS23.003)
+     * - Key Identifier is a null-terminated string of the form "<Key>=<Value>"
+     */
+    typedef vec<uint8_t> EapSimEncryptedIdentity;
+
+    /**
+     * Set EAP encrypted IMSI Identity for this network.
+     *
+     * @param identity Identity string built from the encrypted IMSI.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    setEapEncryptedImsiIdentity(EapSimEncryptedIdentity identity)
+        generates (SupplicantStatus status);
+
+    /**
+     * Used to send a response to the
+     * |ISupplicantNetworkCallback.onNetworkEapIdentityRequest| request.
+     *
+     * @param identity Identity string containing the IMSI.
+     * @param encryptedIdentity Identity string containing the encrypted IMSI.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    sendNetworkEapIdentityResponse_1_1(
+            EapSimIdentity identity,
+            EapSimEncryptedIdentity encryptedIdentity)
+        generates (SupplicantStatus status);
+};