Merge changes from topic "soundtrigger_refactor"

* changes:
  Migrate to new sound trigger middleware service
  Make IAudioPolicyService::{acquire,release}SoundTriggerSession work remotely
diff --git a/apex/Android.bp b/apex/Android.bp
index 42a620b..73dc264 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -41,6 +41,8 @@
 
     // Use a custom AndroidManifest.xml used for API targeting.
     androidManifest: ":com.android.media-androidManifest",
+
+    legacy_android10_support: true,
 }
 
 apex {
@@ -76,6 +78,8 @@
 
     // Use a custom AndroidManifest.xml used for API targeting.
     androidManifest: ":com.android.media.swcodec-androidManifest",
+
+    legacy_android10_support: true,
 }
 
 prebuilt_etc {
diff --git a/camera/Android.bp b/camera/Android.bp
index b288bcf..ea7259a 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -85,6 +85,7 @@
         "aidl/android/hardware/ICameraServiceProxy.aidl",
         "aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl",
         "aidl/android/hardware/camera2/ICameraDeviceUser.aidl",
+        "aidl/android/hardware/camera2/ICameraOfflineSession.aidl",
     ],
     path: "aidl",
 }
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
index 93549e0..cdb7ac3 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -17,6 +17,8 @@
 package android.hardware.camera2;
 
 import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.ICameraDeviceCallbacks;
+import android.hardware.camera2.ICameraOfflineSession;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.params.OutputConfiguration;
 import android.hardware.camera2.params.SessionConfiguration;
@@ -177,4 +179,15 @@
       * @return the currently applied system-wide audio restriction mode
       */
     int getGlobalAudioRestriction();
+
+    /**
+     * Offline processing main entry point
+     *
+     * @param callbacks Object that will receive callbacks from offline session
+     * @param offlineOutputIds The ID of streams that needs to be preserved in offline session
+     *
+     * @return Offline session object.
+     */
+    ICameraOfflineSession switchToOffline(in ICameraDeviceCallbacks callbacks,
+            in Surface[] offlineOutputs);
 }
diff --git a/camera/aidl/android/hardware/camera2/ICameraOfflineSession.aidl b/camera/aidl/android/hardware/camera2/ICameraOfflineSession.aidl
new file mode 100644
index 0000000..ab030ab
--- /dev/null
+++ b/camera/aidl/android/hardware/camera2/ICameraOfflineSession.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2019 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.camera2;
+
+ /** @hide */
+interface ICameraOfflineSession
+{
+    void disconnect();
+}
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 825f308..0652cbb 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -1311,7 +1311,7 @@
     /**
      * <p>List of the maximum number of regions that can be used for metering in
      * auto-exposure (AE), auto-white balance (AWB), and auto-focus (AF);
-     * this corresponds to the the maximum number of elements in
+     * this corresponds to the maximum number of elements in
      * ACAMERA_CONTROL_AE_REGIONS, ACAMERA_CONTROL_AWB_REGIONS,
      * and ACAMERA_CONTROL_AF_REGIONS.</p>
      *
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 6f85960..8c0ecf2 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -1631,8 +1631,12 @@
         {
             *offset += chunk_size;
 
-            if (mLastTrack == NULL)
+            // the absolute minimum size of a compliant mett box is 11 bytes:
+            // 6 byte reserved, 2 byte index, null byte, one char mime_format, null byte
+            // The resulting mime_format would be invalid at that size though.
+            if (mLastTrack == NULL || chunk_data_size < 11) {
                 return ERROR_MALFORMED;
+            }
 
             auto buffer = heapbuffer<uint8_t>(chunk_data_size);
             if (buffer.get() == NULL) {
@@ -1644,10 +1648,24 @@
                 return ERROR_IO;
             }
 
+            // ISO-14496-12:
+            // int8 reserved[6];               // should be all zeroes
+            // int16_t data_reference_index;
+            // char content_encoding[];        // null terminated, optional (= just the null byte)
+            // char mime_format[];             // null terminated, mandatory
+            // optional other boxes
+            //
+            // API < 29:
+            // char mime_format[];             // null terminated
+            //
+            // API >= 29
+            // char mime_format[];             // null terminated
+            // char mime_format[];             // null terminated
+
             // Prior to API 29, the metadata track was not compliant with ISO/IEC
             // 14496-12-2015. This led to some ISO-compliant parsers failing to read the
             // metatrack. As of API 29 and onwards, a change was made to metadata track to
-            // make it compliant with the standard. The workaround is to write the
+            // make it somewhat compatible with the standard. The workaround is to write the
             // null-terminated mime_format string twice. This allows compliant parsers to
             // read the missing reserved, data_reference_index, and content_encoding fields
             // from the first mime_type string. The actual mime_format field would then be
@@ -1656,27 +1674,27 @@
             // as it would only read the first null-terminated mime_format string. To enable
             // reading metadata tracks generated from both the non-compliant and compliant
             // formats, a check needs to be done to see which format is used.
-            int null_pos = 0;
-            const unsigned char *str = buffer.get();
-            while (null_pos < chunk_data_size) {
-              if (*(str + null_pos) == '\0') {
-                break;
-              }
-              ++null_pos;
-            }
+            const char *str = (const char*) buffer.get();
+            size_t string_length = strnlen(str, chunk_data_size);
 
-            if (null_pos == chunk_data_size - 1) {
-              // This is not a standard ompliant metadata track.
-              String8 mimeFormat((const char *)(buffer.get()), chunk_data_size);
-              AMediaFormat_setString(mLastTrack->meta,
-                  AMEDIAFORMAT_KEY_MIME, mimeFormat.string());
+            if (string_length == chunk_data_size - 1) {
+                // This is likely a pre API 29 file, since it's a single null terminated
+                // string filling the entire box.
+                AMediaFormat_setString(mLastTrack->meta, AMEDIAFORMAT_KEY_MIME, str);
             } else {
-              // This is a standard compliant metadata track.
-              String8 contentEncoding((const char *)(buffer.get() + 8));
-              String8 mimeFormat((const char *)(buffer.get() + 8 + contentEncoding.size() + 1),
-                  chunk_data_size - 8 - contentEncoding.size() - 1);
-              AMediaFormat_setString(mLastTrack->meta,
-                  AMEDIAFORMAT_KEY_MIME, mimeFormat.string());
+                // This might be a fully compliant metadata track, a "double mime" compatibility
+                // track, or anything else, including a single non-terminated string, so we need
+                // to determine the length of each string we want to parse out of the box.
+                size_t encoding_length = strnlen(str + 8, chunk_data_size - 8);
+                if (encoding_length + 8 >= chunk_data_size - 2) {
+                    // the encoding extends to the end of the box, so there's no mime_format
+                    return ERROR_MALFORMED;
+                }
+                String8 contentEncoding(str + 8, encoding_length);
+                String8 mimeFormat(str + 8 + encoding_length + 1,
+                        chunk_data_size - 8 - encoding_length - 1);
+                AMediaFormat_setString(mLastTrack->meta,
+                        AMEDIAFORMAT_KEY_MIME, mimeFormat.string());
             }
             break;
         }
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index cd3ac1f..342ceb6 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -323,25 +323,45 @@
     if (mDevice == 0) return NO_INIT;
     if (patch == nullptr) return BAD_VALUE;
 
+#if MAJOR_VERSION < 6
     if (*patch != AUDIO_PATCH_HANDLE_NONE) {
         status_t status = releaseAudioPatch(*patch);
         ALOGW_IF(status != NO_ERROR, "%s error %d releasing patch handle %d",
             __func__, status, *patch);
+        *patch = AUDIO_PATCH_HANDLE_NONE;
     }
+#endif
 
     hidl_vec<AudioPortConfig> hidlSources, hidlSinks;
     HidlUtils::audioPortConfigsFromHal(num_sources, sources, &hidlSources);
     HidlUtils::audioPortConfigsFromHal(num_sinks, sinks, &hidlSinks);
-    Result retval;
-    Return<void> ret = mDevice->createAudioPatch(
-            hidlSources, hidlSinks,
-            [&](Result r, AudioPatchHandle hidlPatch) {
-                retval = r;
-                if (retval == Result::OK) {
-                    *patch = static_cast<audio_patch_handle_t>(hidlPatch);
-                }
-            });
-    return processReturn("createAudioPatch", ret, retval);
+    Result retval = Result::OK;
+    Return<void> ret;
+    std::string methodName = "createAudioPatch";
+    if (*patch == AUDIO_PATCH_HANDLE_NONE) {  // always true for MAJOR_VERSION < 6
+        ret = mDevice->createAudioPatch(
+                hidlSources, hidlSinks,
+                [&](Result r, AudioPatchHandle hidlPatch) {
+                    retval = r;
+                    if (retval == Result::OK) {
+                        *patch = static_cast<audio_patch_handle_t>(hidlPatch);
+                    }
+                });
+    } else {
+#if MAJOR_VERSION >= 6
+        ret = mDevice->updateAudioPatch(
+                *patch,
+                hidlSources, hidlSinks,
+                [&](Result r, AudioPatchHandle hidlPatch) {
+                    retval = r;
+                    if (retval == Result::OK) {
+                        *patch = static_cast<audio_patch_handle_t>(hidlPatch);
+                    }
+                });
+        methodName = "updateAudioPatch";
+#endif
+    }
+    return processReturn(methodName.c_str(), ret, retval);
 }
 
 status_t DeviceHalHidl::releaseAudioPatch(audio_patch_handle_t patch) {
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index a49e72e..4657f9e 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -418,7 +418,7 @@
                     sp<IMediaExtractorService> mediaExService(
                             interface_cast<IMediaExtractorService>(binder));
                     sp<IDataSource> source;
-                    mediaExService->makeIDataSource(mFd, mOffset, mLength, &source);
+                    mediaExService->makeIDataSource(base::unique_fd(dup(mFd.get())), mOffset, mLength, &source);
                     ALOGV("IDataSource(FileSource): %p %d %lld %lld",
                             source.get(), mFd.get(), (long long)mOffset, (long long)mLength);
                     if (source.get() != nullptr) {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 257dd0f..b69f347 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -101,6 +101,10 @@
 static const char *kCodecLatencyHist = "android.media.mediacodec.latency.hist"; /* in us */
 static const char *kCodecLatencyUnknown = "android.media.mediacodec.latency.unknown";
 
+static const char *kCodecNumLowLatencyModeOn = "android.media.mediacodec.low-latency.on";  /* 0..n */
+static const char *kCodecNumLowLatencyModeOff = "android.media.mediacodec.low-latency.off";  /* 0..n */
+static const char *kCodecFirstFrameIndexLowLatencyModeOn = "android.media.mediacodec.low-latency.first-frame";  /* 0..n */
+
 // the kCodecRecent* fields appear only in getMetrics() results
 static const char *kCodecRecentLatencyMax = "android.media.mediacodec.recent.max";      /* in us */
 static const char *kCodecRecentLatencyMin = "android.media.mediacodec.recent.min";      /* in us */
@@ -583,7 +587,12 @@
       mHaveInputSurface(false),
       mHavePendingInputBuffers(false),
       mCpuBoostRequested(false),
-      mLatencyUnknown(0) {
+      mLatencyUnknown(0),
+      mNumLowLatencyEnables(0),
+      mNumLowLatencyDisables(0),
+      mIsLowLatencyModeOn(false),
+      mIndexOfFirstFrameWhenLowLatencyOn(-1),
+      mInputBufferCounter(0) {
     if (uid == kNoUid) {
         mUid = AIBinder_getCallingUid();
     } else {
@@ -616,6 +625,16 @@
         }
         mRecentHead = 0;
     }
+
+    {
+        Mutex::Autolock al(mLatencyLock);
+        mBuffersInFlight.clear();
+        mNumLowLatencyEnables = 0;
+        mNumLowLatencyDisables = 0;
+        mIsLowLatencyModeOn = false;
+        mIndexOfFirstFrameWhenLowLatencyOn = -1;
+        mInputBufferCounter = 0;
+    }
 }
 
 void MediaCodec::updateMediametrics() {
@@ -641,6 +660,13 @@
         mediametrics_setInt64(mMetricsHandle, kCodecLatencyUnknown, mLatencyUnknown);
     }
 
+    {
+        Mutex::Autolock al(mLatencyLock);
+        mediametrics_setInt64(mMetricsHandle, kCodecNumLowLatencyModeOn, mNumLowLatencyEnables);
+        mediametrics_setInt64(mMetricsHandle, kCodecNumLowLatencyModeOff, mNumLowLatencyDisables);
+        mediametrics_setInt64(mMetricsHandle, kCodecFirstFrameIndexLowLatencyModeOn,
+                              mIndexOfFirstFrameWhenLowLatencyOn);
+    }
 #if 0
     // enable for short term, only while debugging
     updateEphemeralMediametrics(mMetricsHandle);
@@ -697,6 +723,22 @@
     }
 }
 
+void MediaCodec::updateLowLatency(const sp<AMessage> &msg) {
+    int32_t lowLatency = 0;
+    if (msg->findInt32("low-latency", &lowLatency)) {
+        Mutex::Autolock al(mLatencyLock);
+        if (lowLatency > 0) {
+            ++mNumLowLatencyEnables;
+            // This is just an estimate since low latency mode change happens ONLY at key frame
+            mIsLowLatencyModeOn = true;
+        } else if (lowLatency == 0) {
+            ++mNumLowLatencyDisables;
+            // This is just an estimate since low latency mode change happens ONLY at key frame
+            mIsLowLatencyModeOn = false;
+        }
+    }
+}
+
 bool MediaCodec::Histogram::setup(int nbuckets, int64_t width, int64_t floor)
 {
     if (nbuckets <= 0 || width <= 0) {
@@ -813,6 +855,11 @@
         // XXX: we *could* make sure that the time is later than the end of queue
         // as part of a consistency check...
         mBuffersInFlight.push_back(startdata);
+
+        if (mIsLowLatencyModeOn && mIndexOfFirstFrameWhenLowLatencyOn < 0) {
+            mIndexOfFirstFrameWhenLowLatencyOn = mInputBufferCounter;
+        }
+        ++mInputBufferCounter;
     }
 }
 
@@ -1133,6 +1180,8 @@
         }
     }
 
+    updateLowLatency(format);
+
     msg->setMessage("format", format);
     msg->setInt32("flags", flags);
     msg->setObject("surface", surface);
@@ -3714,6 +3763,7 @@
 }
 
 status_t MediaCodec::onSetParameters(const sp<AMessage> &params) {
+    updateLowLatency(params);
     mCodec->signalSetParameters(params);
 
     return OK;
diff --git a/media/libstagefright/codecs/amrnb/common/Android.bp b/media/libstagefright/codecs/amrnb/common/Android.bp
index 772ebf9..ea8b073 100644
--- a/media/libstagefright/codecs/amrnb/common/Android.bp
+++ b/media/libstagefright/codecs/amrnb/common/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
     name: "libstagefright_amrnb_common",
     vendor_available: true,
 
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 78cb01c..5c5c23a 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -313,6 +313,7 @@
     void updateMediametrics();
     void flushMediametrics();
     void updateEphemeralMediametrics(mediametrics_handle_t item);
+    void updateLowLatency(const sp<AMessage> &msg);
 
     sp<AMessage> mOutputFormat;
     sp<AMessage> mInputFormat;
@@ -440,6 +441,12 @@
     std::deque<BufferFlightTiming_t> mBuffersInFlight;
     Mutex mLatencyLock;
     int64_t mLatencyUnknown;    // buffers for which we couldn't calculate latency
+    int64_t mNumLowLatencyEnables;  // how many times low latency mode is enabled
+    int64_t mNumLowLatencyDisables;  // how many times low latency mode is disabled
+    bool mIsLowLatencyModeOn;  // is low latency mode on currently
+    int64_t mIndexOfFirstFrameWhenLowLatencyOn;  // index of the first frame queued
+                                                 // when low latency is on
+    int64_t mInputBufferCounter;  // number of input buffers queued since last reset/flush
 
     sp<BatteryChecker> mBatteryChecker;
 
diff --git a/media/mtp/IMtpHandle.h b/media/mtp/IMtpHandle.h
index fd14b18..0435e82 100644
--- a/media/mtp/IMtpHandle.h
+++ b/media/mtp/IMtpHandle.h
@@ -16,7 +16,7 @@
 #ifndef _IMTP_HANDLE_H
 #define _IMTP_HANDLE_H
 
-#include <linux/usb/f_mtp.h>
+#include "f_mtp.h"
 
 namespace android {
 
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index af69a10..fdf51b1 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -84,8 +84,8 @@
 //    MTP_OPERATION_SET_OBJECT_PROP_LIST,
 //    MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC,
 //    MTP_OPERATION_SEND_OBJECT_PROP_LIST,
-    MTP_OPERATION_GET_OBJECT_REFERENCES,
-    MTP_OPERATION_SET_OBJECT_REFERENCES,
+//    MTP_OPERATION_GET_OBJECT_REFERENCES,
+//    MTP_OPERATION_SET_OBJECT_REFERENCES,
 //    MTP_OPERATION_SKIP,
     // Android extension for direct file IO
     MTP_OPERATION_GET_PARTIAL_OBJECT_64,
diff --git a/media/mtp/f_mtp.h b/media/mtp/f_mtp.h
new file mode 100644
index 0000000..22ec771
--- /dev/null
+++ b/media/mtp/f_mtp.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _UAPI_LINUX_USB_F_MTP_H
+#define _UAPI_LINUX_USB_F_MTP_H
+#include <linux/ioctl.h>
+#include <linux/types.h>
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct mtp_file_range {
+  int fd;
+  loff_t offset;
+  int64_t length;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  uint16_t command;
+  uint32_t transaction_id;
+};
+struct mtp_event {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  size_t length;
+  void * data;
+};
+#define MTP_SEND_FILE _IOW('M', 0, struct mtp_file_range)
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define MTP_RECEIVE_FILE _IOW('M', 1, struct mtp_file_range)
+#define MTP_SEND_EVENT _IOW('M', 3, struct mtp_event)
+#define MTP_SEND_FILE_WITH_HEADER _IOW('M', 4, struct mtp_file_range)
+#endif
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 8095f52..0b0f9f5 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -27,7 +27,6 @@
 public:
             ~EffectCallbackInterface() override = default;
 
-
     // Trivial methods usually implemented with help from ThreadBase
     virtual audio_io_handle_t io() const = 0;
     virtual bool isOutput() const = 0;
@@ -44,7 +43,7 @@
     virtual uint32_t latency() const { return 0; }
     virtual status_t addEffectToHal(sp<EffectHalInterface> effect) = 0;
     virtual status_t removeEffectFromHal(sp<EffectHalInterface> effect) = 0;
-    virtual void setVolumeForOutput(float left, float right) const;
+    virtual void setVolumeForOutput(float left, float right) const = 0;
     virtual bool disconnectEffectHandle(EffectHandle *handle, bool unpinIfLast) = 0;
     virtual void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
                                              bool enabled,
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index c50a3c6..9cc15cd 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -26,6 +26,7 @@
         "CameraFlashlight.cpp",
         "common/Camera2ClientBase.cpp",
         "common/CameraDeviceBase.cpp",
+        "common/CameraOfflineSessionBase.cpp",
         "common/CameraProviderManager.cpp",
         "common/FrameProcessorBase.cpp",
         "api1/CameraClient.cpp",
@@ -45,6 +46,7 @@
         "api2/HeicCompositeStream.cpp",
         "device1/CameraHardwareInterface.cpp",
         "device3/Camera3Device.cpp",
+        "device3/Camera3OfflineSession.cpp",
         "device3/Camera3Stream.cpp",
         "device3/Camera3IOStreamBase.cpp",
         "device3/Camera3InputStream.cpp",
@@ -110,6 +112,7 @@
         "android.hardware.camera.device@3.3",
         "android.hardware.camera.device@3.4",
         "android.hardware.camera.device@3.5",
+        "android.hardware.camera.device@3.6"
     ],
 
     export_shared_lib_headers: [
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index b704573..18ed3a5 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -2776,6 +2776,20 @@
 
 // ----------------------------------------------------------------------------
 
+sp<CameraService> CameraService::OfflineClient::sCameraService;
+
+status_t CameraService::OfflineClient::startCameraOps() {
+    // TODO
+    return OK;
+}
+
+status_t CameraService::OfflineClient::finishCameraOps() {
+    // TODO
+    return OK;
+}
+
+// ----------------------------------------------------------------------------
+
 void CameraService::Client::notifyError(int32_t errorCode,
         const CaptureResultExtras& resultExtras) {
     (void) resultExtras;
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 1f40fc3..dae9c09 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -71,6 +71,7 @@
 public:
     class Client;
     class BasicClient;
+    class OfflineClient;
 
     // The effective API level.  The Camera2 API running in LEGACY mode counts as API_1.
     enum apiLevel {
@@ -401,6 +402,87 @@
         int mCameraId;  // All API1 clients use integer camera IDs
     }; // class Client
 
+
+    // Client for offline session. Note that offline session client does not affect camera service's
+    // client arbitration logic. It is camera HAL's decision to decide whether a normal camera
+    // client is conflicting with existing offline client(s).
+    // The other distinctive difference between offline clients and normal clients is that normal
+    // clients are created through ICameraService binder calls, while the offline session client
+    // is created through ICameraDeviceUser::switchToOffline call.
+    class OfflineClient : public virtual RefBase {
+
+        virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+
+        // Block the client form using the camera
+        virtual void block() = 0;
+
+        // Return the package name for this client
+        virtual String16 getPackageName() const = 0;
+
+        // Notify client about a fatal error
+        // TODO: maybe let impl notify within block?
+        virtual void notifyError(int32_t errorCode,
+                const CaptureResultExtras& resultExtras) = 0;
+
+        // Get the UID of the application client using this
+        virtual uid_t getClientUid() const = 0;
+
+        // Get the PID of the application client using this
+        virtual int getClientPid() const = 0;
+
+        protected:
+            OfflineClient(const sp<CameraService>& cameraService,
+                    const String16& clientPackageName,
+                    const String8& cameraIdStr,
+                    int clientPid,
+                    uid_t clientUid,
+                    int servicePid): mCameraIdStr(cameraIdStr),
+                            mClientPackageName(clientPackageName), mClientPid(clientPid),
+                            mClientUid(clientUid), mServicePid(servicePid) {
+                if (sCameraService == nullptr) {
+                    sCameraService = cameraService;
+                }
+            }
+
+            virtual ~OfflineClient() { /*TODO*/ }
+
+            // these are initialized in the constructor.
+            static sp<CameraService>        sCameraService;
+            const String8                   mCameraIdStr;
+            String16                        mClientPackageName;
+            pid_t                           mClientPid;
+            const uid_t                     mClientUid;
+            const pid_t                     mServicePid;
+            bool                            mDisconnected;
+
+            // - The app-side Binder interface to receive callbacks from us
+            sp<IBinder>                     mRemoteBinder;   // immutable after constructor
+
+            // permissions management
+            status_t                        startCameraOps();
+            status_t                        finishCameraOps();
+
+        private:
+            std::unique_ptr<AppOpsManager>  mAppOpsManager = nullptr;
+
+            class OpsCallback : public BnAppOpsCallback {
+            public:
+                explicit OpsCallback(wp<OfflineClient> client) : mClient(client) {}
+                virtual void opChanged(int32_t /*op*/, const String16& /*packageName*/) {
+                    //TODO
+                }
+
+            private:
+                wp<OfflineClient> mClient;
+
+            }; // class OpsCallback
+
+            sp<OpsCallback> mOpsCallback;
+
+            // IAppOpsCallback interface, indirected through opListener
+            // virtual void opChanged(int32_t op, const String16& packageName);
+    }; // class OfflineClient
+
     /**
      * A listener class that implements the LISTENER interface for use with a ClientManager, and
      * implements the following methods:
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 27bebde..28421ba 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -1901,6 +1901,80 @@
     return binder::Status::ok();
 }
 
+binder::Status CameraDeviceClient::switchToOffline(
+        const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
+        const std::vector<view::Surface>& offlineOutputs,
+        /*out*/
+        sp<hardware::camera2::ICameraOfflineSession>* session) {
+    ATRACE_CALL();
+
+    binder::Status res;
+    if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    if (!mDevice.get()) {
+        return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
+    }
+
+    if (offlineOutputs.empty()) {
+        String8 msg = String8::format("Offline outputs must not be empty");
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+    }
+
+    if (session == nullptr) {
+        String8 msg = String8::format("Invalid offline session");
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+    }
+
+    std::vector<int32_t> offlineStreamIds(offlineOutputs.size());
+    for (auto& surface : offlineOutputs) {
+        sp<IBinder> binder = IInterface::asBinder(surface.graphicBufferProducer);
+        ssize_t index = mStreamMap.indexOfKey(binder);
+        if (index == NAME_NOT_FOUND) {
+            String8 msg = String8::format("Offline output is invalid");
+            ALOGE("%s: %s", __FUNCTION__, msg.string());
+            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+        }
+        // TODO: Also check whether the offline output is supported by Hal for offline mode.
+
+        sp<Surface> s = new Surface(surface.graphicBufferProducer);
+        bool isCompositeStream = camera3::DepthCompositeStream::isDepthCompositeStream(s);
+        isCompositeStream |= camera3::HeicCompositeStream::isHeicCompositeStream(s);
+        if (isCompositeStream) {
+            // TODO: Add composite specific handling
+        } else {
+            offlineStreamIds.push_back(mStreamMap.valueAt(index).streamId());
+        }
+    }
+
+    sp<CameraOfflineSessionBase> offlineSession;
+    auto ret = mDevice->switchToOffline(offlineStreamIds, &offlineSession);
+    if (ret != OK) {
+        return STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                "Camera %s: Error switching to offline mode: %s (%d)",
+                mCameraIdStr.string(), strerror(ret), ret);
+    }
+
+    sp<CameraOfflineSessionClient> offlineClient = new CameraOfflineSessionClient(sCameraService,
+            offlineSession, cameraCb, mClientPackageName, mCameraIdStr, mClientPid, mClientUid,
+            mServicePid);
+    ret = offlineClient->initialize();
+    if (ret == OK) {
+        // TODO: We need to update mStreamMap, mConfiguredOutputs
+    } else {
+        return STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                "Camera %s: Failed to initilize offline session: %s (%d)",
+                mCameraIdStr.string(), strerror(ret), ret);
+    }
+
+    *session = offlineClient;
+
+    return binder::Status::ok();
+}
+
 status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) {
     return BasicClient::dump(fd, args);
 }
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 7efc5ab..0a8f377 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -23,6 +23,7 @@
 #include <camera/camera2/SessionConfiguration.h>
 #include <camera/camera2/SubmitInfo.h>
 
+#include "CameraOfflineSessionClient.h"
 #include "CameraService.h"
 #include "common/FrameProcessorBase.h"
 #include "common/Camera2ClientBase.h"
@@ -157,6 +158,12 @@
 
     virtual binder::Status getGlobalAudioRestriction(/*out*/int32_t* outMode) override;
 
+    virtual binder::Status switchToOffline(
+            const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
+            const std::vector<view::Surface>& offlineOutputs,
+            /*out*/
+            sp<hardware::camera2::ICameraOfflineSession>* session) override;
+
     /**
      * Interface used by CameraService
      */
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
new file mode 100644
index 0000000..cb83e29
--- /dev/null
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 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_SERVERS_CAMERA_PHOTOGRAPHY_CAMERAOFFLINESESSIONCLIENT_H
+#define ANDROID_SERVERS_CAMERA_PHOTOGRAPHY_CAMERAOFFLINESESSIONCLIENT_H
+
+#include <android/hardware/camera2/BnCameraOfflineSession.h>
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+#include "CameraService.h"
+
+namespace android {
+
+using android::hardware::camera2::ICameraDeviceCallbacks;
+
+class CameraOfflineSessionClient :
+        public CameraService::OfflineClient,
+        public hardware::camera2::BnCameraOfflineSession
+        // public camera2::FrameProcessorBase::FilteredListener?
+{
+public:
+    CameraOfflineSessionClient(
+            const sp<CameraService>& cameraService,
+            sp<CameraOfflineSessionBase> session,
+            const sp<ICameraDeviceCallbacks>& remoteCallback,
+            const String16& clientPackageName,
+            const String8& cameraIdStr,
+            int clientPid, uid_t clientUid, int servicePid) :
+                    CameraService::OfflineClient(cameraService, clientPackageName,
+                            cameraIdStr, clientPid, clientUid, servicePid),
+                            mRemoteCallback(remoteCallback), mOfflineSession(session) {}
+
+    ~CameraOfflineSessionClient() {}
+
+    virtual binder::Status disconnect() override { return binder::Status::ok(); }
+
+    virtual status_t dump(int /*fd*/, const Vector<String16>& /*args*/) override {
+        return OK;
+    }
+
+    // Block the client form using the camera
+    virtual void block() override {};
+
+    // Return the package name for this client
+    virtual String16 getPackageName() const override { String16 ret; return ret; };
+
+    // Notify client about a fatal error
+    // TODO: maybe let impl notify within block?
+    virtual void notifyError(int32_t /*errorCode*/,
+            const CaptureResultExtras& /*resultExtras*/) override {}
+
+    // Get the UID of the application client using this
+    virtual uid_t getClientUid() const override { return 0; }
+
+    // Get the PID of the application client using this
+    virtual int getClientPid() const override { return 0; }
+
+    status_t initialize() {
+        // TODO: Talk to camera service to add the offline session client book keeping
+        return OK;
+    }
+private:
+    sp<CameraOfflineSessionBase> mSession;
+
+    sp<hardware::camera2::ICameraDeviceCallbacks> mRemoteCallback;
+    // This class is responsible to convert HAL callbacks to AIDL callbacks
+
+    sp<CameraOfflineSessionBase> mOfflineSession;
+};
+
+} // namespace android
+
+#endif // ANDROID_SERVERS_CAMERA_PHOTOGRAPHY_CAMERAOFFLINESESSIONCLIENT_H
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 935bc37..1026fdf 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -35,6 +35,8 @@
 #include "device3/Camera3StreamInterface.h"
 #include "binder/Status.h"
 
+#include "CameraOfflineSessionBase.h"
+
 namespace android {
 
 class CameraProviderManager;
@@ -389,6 +391,13 @@
      * requests to complete, based on their settings
      */
     virtual nsecs_t getExpectedInFlightDuration() = 0;
+
+    /**
+     * switch to offline session
+     */
+    virtual status_t switchToOffline(
+            const std::vector<int32_t>& streamsToKeep,
+            /*out*/ sp<CameraOfflineSessionBase>* session) = 0;
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/common/CameraOfflineSessionBase.cpp b/services/camera/libcameraservice/common/CameraOfflineSessionBase.cpp
new file mode 100644
index 0000000..ff673a9
--- /dev/null
+++ b/services/camera/libcameraservice/common/CameraOfflineSessionBase.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 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 "CameraOfflineSessionBase.h"
+
+namespace android {
+
+/**
+ * Base class destructors
+ */
+CameraOfflineSessionBase::~CameraOfflineSessionBase() {
+}
+
+} // namespace android
diff --git a/services/camera/libcameraservice/common/CameraOfflineSessionBase.h b/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
new file mode 100644
index 0000000..3862521
--- /dev/null
+++ b/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 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_SERVERS_CAMERA_CAMERAOFFLINESESSIONBASE_H
+#define ANDROID_SERVERS_CAMERA_CAMERAOFFLINESESSIONBASE_H
+
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Timers.h>
+
+#include "camera/CaptureResult.h"
+
+namespace android {
+
+class CameraOfflineSessionBase : public virtual RefBase {
+  public:
+    virtual ~CameraOfflineSessionBase();
+
+    // The session's original camera ID
+    virtual const String8& getId() const = 0;
+
+    virtual status_t disconnect() = 0;
+
+    virtual status_t dump(int fd) = 0;
+
+    virtual status_t abort() = 0;
+
+    /**
+     * Capture result passing
+     */
+    virtual status_t waitForNextFrame(nsecs_t timeout) = 0;
+
+    virtual status_t getNextResult(CaptureResult *frame) = 0;
+
+    // TODO: notification passing path
+}; // class CameraOfflineSessionBase
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 2541365..4e5c8d6 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -58,6 +58,7 @@
 #include "device3/Camera3InputStream.h"
 #include "device3/Camera3DummyStream.h"
 #include "device3/Camera3SharedOutputStream.h"
+#include "device3/Camera3OfflineSession.h"
 #include "CameraService.h"
 #include "utils/CameraThreadState.h"
 
@@ -206,7 +207,15 @@
             ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
     }
 
-    mInterface = new HalInterface(session, queue, mUseHalBufManager);
+    camera_metadata_entry_t capabilities = mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+    for (size_t i = 0; i < capabilities.count; i++) {
+        uint8_t capability = capabilities.data.u8[i];
+        if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING) {
+            mSupportOfflineProcessing = true;
+        }
+    }
+
+    mInterface = new HalInterface(session, queue, mUseHalBufManager, mSupportOfflineProcessing);
     std::string providerType;
     mVendorTagId = manager->getProviderTagIdLocked(mId.string());
     mTagMonitor.initialize(mVendorTagId);
@@ -227,9 +236,8 @@
             maxVersion.get_major(), maxVersion.get_minor());
 
     bool isMonochrome = false;
-    camera_metadata_entry_t entry = mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
-    for (size_t i = 0; i < entry.count; i++) {
-        uint8_t capability = entry.data.u8[i];
+    for (size_t i = 0; i < capabilities.count; i++) {
+        uint8_t capability = capabilities.data.u8[i];
         if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) {
             isMonochrome = true;
         }
@@ -4045,13 +4053,18 @@
 Camera3Device::HalInterface::HalInterface(
             sp<ICameraDeviceSession> &session,
             std::shared_ptr<RequestMetadataQueue> queue,
-            bool useHalBufManager) :
+            bool useHalBufManager, bool supportOfflineProcessing) :
         mHidlSession(session),
         mRequestMetadataQueue(queue),
         mUseHalBufManager(useHalBufManager),
-        mIsReconfigurationQuerySupported(true) {
+        mIsReconfigurationQuerySupported(true),
+        mSupportOfflineProcessing(supportOfflineProcessing) {
     // Check with hardware service manager if we can downcast these interfaces
     // Somewhat expensive, so cache the results at startup
+    auto castResult_3_6 = device::V3_6::ICameraDeviceSession::castFrom(mHidlSession);
+    if (castResult_3_6.isOk()) {
+        mHidlSession_3_6 = castResult_3_6;
+    }
     auto castResult_3_5 = device::V3_5::ICameraDeviceSession::castFrom(mHidlSession);
     if (castResult_3_5.isOk()) {
         mHidlSession_3_5 = castResult_3_5;
@@ -4066,18 +4079,22 @@
     }
 }
 
-Camera3Device::HalInterface::HalInterface() : mUseHalBufManager(false) {}
+Camera3Device::HalInterface::HalInterface() :
+        mUseHalBufManager(false),
+        mSupportOfflineProcessing(false) {}
 
 Camera3Device::HalInterface::HalInterface(const HalInterface& other) :
         mHidlSession(other.mHidlSession),
         mRequestMetadataQueue(other.mRequestMetadataQueue),
-        mUseHalBufManager(other.mUseHalBufManager) {}
+        mUseHalBufManager(other.mUseHalBufManager),
+        mSupportOfflineProcessing(other.mSupportOfflineProcessing) {}
 
 bool Camera3Device::HalInterface::valid() {
     return (mHidlSession != nullptr);
 }
 
 void Camera3Device::HalInterface::clear() {
+    mHidlSession_3_6.clear();
     mHidlSession_3_5.clear();
     mHidlSession_3_4.clear();
     mHidlSession_3_3.clear();
@@ -4753,6 +4770,38 @@
     }
 }
 
+status_t Camera3Device::HalInterface::switchToOffline(
+        const std::vector<int32_t>& streamsToKeep,
+        /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+        /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession) {
+    ATRACE_NAME("CameraHal::switchToOffline");
+    if (!valid() || mHidlSession_3_6 == nullptr) {
+        ALOGE("%s called on invalid camera!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    if (offlineSessionInfo == nullptr || offlineSession == nullptr) {
+        ALOGE("%s: offlineSessionInfo and offlineSession must not be null!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    common::V1_0::Status status = common::V1_0::Status::INTERNAL_ERROR;
+
+    auto resultCallback =
+        [&status, &offlineSessionInfo, &offlineSession] (auto s, auto info, auto session) {
+                status = s;
+                *offlineSessionInfo = info;
+                *offlineSession = session;
+        };
+    auto err = mHidlSession_3_6->switchToOffline(streamsToKeep, resultCallback);
+
+    if (!err.isOk()) {
+        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+        return DEAD_OBJECT;
+    }
+    return CameraProviderManager::mapToStatusT(status);
+}
+
 void Camera3Device::HalInterface::getInflightBufferKeys(
         std::vector<std::pair<int32_t, int32_t>>* out) {
     std::lock_guard<std::mutex> lock(mInflightLock);
@@ -5524,6 +5573,7 @@
         Mutex::Autolock l(mRequestLock);
         mNextRequests.clear();
     }
+    mRequestSubmittedSignal.signal();
 
     return submitRequestSuccess;
 }
@@ -5903,6 +5953,32 @@
     mStreamIdsToBeDrained = streamIds;
 }
 
+status_t Camera3Device::RequestThread::switchToOffline(
+        const std::vector<int32_t>& streamsToKeep,
+        /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+        /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession) {
+    Mutex::Autolock l(mRequestLock);
+    clearRepeatingRequestsLocked(/*lastFrameNumber*/nullptr);
+
+    // Theoretically we should also check for mRepeatingRequests.empty(), but the API interface
+    // is serialized by mInterfaceLock so skip that check.
+    bool queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
+    while (!queueEmpty) {
+        status_t res = mRequestSubmittedSignal.waitRelative(mRequestLock, kRequestSubmitTimeout);
+        if (res == TIMED_OUT) {
+            ALOGE("%s: request thread failed to submit a request within timeout!", __FUNCTION__);
+            return res;
+        } else if (res != OK) {
+            ALOGE("%s: request thread failed to submit a request: %s (%d)!",
+                    __FUNCTION__, strerror(-res), res);
+            return res;
+        }
+        queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
+    }
+    return mInterface->switchToOffline(
+            streamsToKeep, offlineSessionInfo, offlineSession);
+}
+
 nsecs_t Camera3Device::getExpectedInFlightDuration() {
     ATRACE_CALL();
     Mutex::Autolock al(mInFlightLock);
@@ -6812,4 +6888,34 @@
     return res;
 }
 
+status_t Camera3Device::switchToOffline(
+        const std::vector<int32_t>& streamsToKeep,
+        /*out*/ sp<CameraOfflineSessionBase>* session) {
+    ATRACE_CALL();
+    if (session == nullptr) {
+        ALOGE("%s: session must not be null", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock il(mInterfaceLock);
+    Mutex::Autolock l(mLock);
+
+    // 1. Stop repeating request, wait until request thread submitted all requests, then
+    //    call HAL switchToOffline
+    hardware::camera::device::V3_6::CameraOfflineSessionInfo offlineSessionInfo;
+    sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession;
+
+    mRequestThread->switchToOffline(streamsToKeep, &offlineSessionInfo, &offlineSession);
+
+
+    // 2. Verify offlineSessionInfo
+    // 3. create Camera3OfflineSession and transfer object ownership
+    //   (streams, inflight requests, buffer caches)
+    *session = new Camera3OfflineSession(mId);
+
+    // 4. Delete unneeded streams
+    // 5. Verify Camera3Device is in unconfigured state
+    return OK;
+}
+
 }; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 2573b48..eabc44d 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -34,6 +34,7 @@
 #include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
 #include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
 #include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
 #include <android/hardware/camera/device/3.2/ICameraDeviceCallback.h>
 #include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
 #include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
@@ -196,6 +197,9 @@
 
     nsecs_t getExpectedInFlightDuration() override;
 
+    status_t switchToOffline(const std::vector<int32_t>& streamsToKeep,
+            /*out*/ sp<CameraOfflineSessionBase>* session) override;
+
     /**
      * Helper functions to map between framework and HIDL values
      */
@@ -282,7 +286,7 @@
       public:
         HalInterface(sp<hardware::camera::device::V3_2::ICameraDeviceSession> &session,
                      std::shared_ptr<RequestMetadataQueue> queue,
-                     bool useHalBufManager);
+                     bool useHalBufManager, bool supportOfflineProcessing);
         HalInterface(const HalInterface &other);
         HalInterface();
 
@@ -316,6 +320,11 @@
         bool isReconfigurationRequired(CameraMetadata& oldSessionParams,
                 CameraMetadata& newSessionParams);
 
+        status_t switchToOffline(
+                const std::vector<int32_t>& streamsToKeep,
+                /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+                /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession);
+
         // method to extract buffer's unique ID
         // return pair of (newlySeenBuffer?, bufferId)
         std::pair<bool, uint64_t> getBufferId(const buffer_handle_t& buf, int streamId);
@@ -352,6 +361,8 @@
         sp<hardware::camera::device::V3_4::ICameraDeviceSession> mHidlSession_3_4;
         // Valid if ICameraDeviceSession is @3.5 or newer
         sp<hardware::camera::device::V3_5::ICameraDeviceSession> mHidlSession_3_5;
+        // Valid if ICameraDeviceSession is @3.6 or newer
+        sp<hardware::camera::device::V3_6::ICameraDeviceSession> mHidlSession_3_6;
 
         std::shared_ptr<RequestMetadataQueue> mRequestMetadataQueue;
 
@@ -424,6 +435,8 @@
 
         const bool mUseHalBufManager;
         bool mIsReconfigurationQuerySupported;
+
+        const bool mSupportOfflineProcessing;
     };
 
     sp<HalInterface> mInterface;
@@ -842,6 +855,11 @@
 
         void signalPipelineDrain(const std::vector<int>& streamIds);
 
+        status_t switchToOffline(
+                const std::vector<int32_t>& streamsToKeep,
+                /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+                /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession);
+
       protected:
 
         virtual bool threadLoop();
@@ -862,6 +880,9 @@
 
         static const nsecs_t kRequestTimeout = 50e6; // 50 ms
 
+        // TODO: does this need to be adjusted for long exposure requests?
+        static const nsecs_t kRequestSubmitTimeout = 200e6; // 200 ms
+
         // Used to prepare a batch of requests.
         struct NextRequest {
             sp<CaptureRequest>              captureRequest;
@@ -936,6 +957,7 @@
 
         Mutex              mRequestLock;
         Condition          mRequestSignal;
+        Condition          mRequestSubmittedSignal;
         RequestList        mRequestQueue;
         RequestList        mRepeatingRequests;
         // The next batch of requests being prepped for submission to the HAL, no longer
@@ -1364,6 +1386,9 @@
     // Fix up result metadata for monochrome camera.
     bool mNeedFixupMonochromeTags;
     status_t fixupMonochromeTags(const CameraMetadata& deviceInfo, CameraMetadata& resultMetadata);
+
+    // Whether HAL supports offline processing capability.
+    bool mSupportOfflineProcessing = false;
 }; // class Camera3Device
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp b/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
new file mode 100644
index 0000000..dc5cbb3
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2019 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 "Camera3-OffLnSsn"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0  // Per-frame verbose logging
+
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
+
+#include <inttypes.h>
+
+#include <utils/Trace.h>
+
+#include "device3/Camera3OfflineSession.h"
+#include "device3/Camera3OutputStream.h"
+#include "device3/Camera3InputStream.h"
+#include "device3/Camera3SharedOutputStream.h"
+
+using namespace android::camera3;
+using namespace android::hardware::camera;
+
+namespace android {
+
+Camera3OfflineSession::Camera3OfflineSession(const String8 &id):
+        mId(id)
+{
+    ATRACE_CALL();
+    ALOGV("%s: Created offline session for camera %s", __FUNCTION__, mId.string());
+}
+
+Camera3OfflineSession::~Camera3OfflineSession()
+{
+    ATRACE_CALL();
+    ALOGV("%s: Tearing down offline session for camera id %s", __FUNCTION__, mId.string());
+}
+
+const String8& Camera3OfflineSession::getId() const {
+    return mId;
+}
+
+status_t Camera3OfflineSession::initialize(
+        sp<hardware::camera::device::V3_6::ICameraOfflineSession> /*hidlSession*/) {
+    ATRACE_CALL();
+    return OK;
+}
+
+status_t Camera3OfflineSession::dump(int /*fd*/) {
+    ATRACE_CALL();
+    return OK;
+}
+
+status_t Camera3OfflineSession::abort() {
+    ATRACE_CALL();
+    return OK;
+}
+
+status_t Camera3OfflineSession::disconnect() {
+    ATRACE_CALL();
+    return OK;
+}
+
+status_t Camera3OfflineSession::waitForNextFrame(nsecs_t /*timeout*/) {
+    ATRACE_CALL();
+    return OK;
+}
+
+status_t Camera3OfflineSession::getNextResult(CaptureResult* /*frame*/) {
+    ATRACE_CALL();
+    return OK;
+}
+
+hardware::Return<void> Camera3OfflineSession::processCaptureResult_3_4(
+        const hardware::hidl_vec<
+                hardware::camera::device::V3_4::CaptureResult>& /*results*/) {
+    return hardware::Void();
+}
+
+hardware::Return<void> Camera3OfflineSession::processCaptureResult(
+        const hardware::hidl_vec<
+                hardware::camera::device::V3_2::CaptureResult>& /*results*/) {
+    return hardware::Void();
+}
+
+hardware::Return<void> Camera3OfflineSession::notify(
+        const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& /*msgs*/) {
+    return hardware::Void();
+}
+
+hardware::Return<void> Camera3OfflineSession::requestStreamBuffers(
+        const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& /*bufReqs*/,
+        requestStreamBuffers_cb /*_hidl_cb*/) {
+    return hardware::Void();
+}
+
+hardware::Return<void> Camera3OfflineSession::returnStreamBuffers(
+        const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& /*buffers*/) {
+    return hardware::Void();
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.h b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
new file mode 100644
index 0000000..30e8c4f
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2019 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_SERVERS_CAMERA3OFFLINESESSION_H
+#define ANDROID_SERVERS_CAMERA3OFFLINESESSION_H
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+#include <android/hardware/camera/device/3.6/ICameraOfflineSession.h>
+#include <fmq/MessageQueue.h>
+
+#include "common/CameraOfflineSessionBase.h"
+
+#include "device3/Camera3BufferManager.h"
+#include "device3/DistortionMapper.h"
+#include "utils/TagMonitor.h"
+#include "utils/LatencyHistogram.h"
+#include <camera_metadata_hidden.h>
+
+namespace android {
+
+namespace camera3 {
+
+class Camera3Stream;
+class Camera3OutputStreamInterface;
+class Camera3StreamInterface;
+
+} // namespace camera3
+
+/**
+ * Camera3OfflineSession for offline session defined in HIDL ICameraOfflineSession@3.6 or higher
+ */
+class Camera3OfflineSession :
+            public CameraOfflineSessionBase,
+            virtual public hardware::camera::device::V3_5::ICameraDeviceCallback {
+
+  public:
+
+    // initialize by Camera3Device. Camera3Device must send all info in separate argument.
+    // monitored tags
+    // mUseHalBufManager
+    // mUsePartialResult
+    // mNumPartialResults
+    explicit Camera3OfflineSession(const String8& id);
+
+    virtual ~Camera3OfflineSession();
+
+    status_t initialize(
+        sp<hardware::camera::device::V3_6::ICameraOfflineSession> hidlSession);
+
+    /**
+     * CameraOfflineSessionBase interface
+     */
+    const String8& getId() const override;
+
+    status_t disconnect() override;
+
+    status_t dump(int fd) override;
+
+    status_t abort() override;
+
+    // methods for capture result passing
+    status_t waitForNextFrame(nsecs_t timeout) override;
+    status_t getNextResult(CaptureResult *frame) override;
+
+    // TODO: methods for notification (error/idle/finished etc) passing
+
+    /**
+     * End of CameraOfflineSessionBase interface
+     */
+
+    /**
+     * HIDL ICameraDeviceCallback interface
+     */
+
+    /**
+     * Implementation of android::hardware::camera::device::V3_5::ICameraDeviceCallback
+     */
+
+    hardware::Return<void> processCaptureResult_3_4(
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_4::CaptureResult>& results) override;
+    hardware::Return<void> processCaptureResult(
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_2::CaptureResult>& results) override;
+    hardware::Return<void> notify(
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_2::NotifyMsg>& msgs) override;
+
+    hardware::Return<void> requestStreamBuffers(
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+            requestStreamBuffers_cb _hidl_cb) override;
+
+    hardware::Return<void> returnStreamBuffers(
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_2::StreamBuffer>& buffers) override;
+
+    /**
+     * End of CameraOfflineSessionBase interface
+     */
+
+  private:
+
+    // Camera device ID
+    const String8 mId;
+
+}; // class Camera3OfflineSession
+
+}; // namespace android
+
+#endif
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index 9e814d1..a6cd224 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -61,13 +61,11 @@
 }
 
 ::android::binder::Status MediaExtractorService::makeIDataSource(
-        const base::unique_fd &fd,
+        base::unique_fd fd,
         int64_t offset,
         int64_t length,
         ::android::sp<::android::IDataSource>* _aidl_return) {
-    // the caller will close the fd owned by the unique_fd upon return of this function,
-    // so we need to dup() it to retain it.
-    sp<DataSource> source = DataSourceFactory::getInstance()->CreateFromFd(dup(fd.get()), offset, length);
+    sp<DataSource> source = DataSourceFactory::getInstance()->CreateFromFd(fd.release(), offset, length);
     *_aidl_return = CreateIDataSourceFromDataSource(source);
     return binder::Status::ok();
 }
diff --git a/services/mediaextractor/MediaExtractorService.h b/services/mediaextractor/MediaExtractorService.h
index 1b61c4b..1b40bf9 100644
--- a/services/mediaextractor/MediaExtractorService.h
+++ b/services/mediaextractor/MediaExtractorService.h
@@ -37,7 +37,7 @@
             ::android::sp<::android::IMediaExtractor>* _aidl_return);
 
     virtual ::android::binder::Status makeIDataSource(
-            const base::unique_fd &fd,
+            base::unique_fd fd,
             int64_t offset,
             int64_t length,
             ::android::sp<::android::IDataSource>* _aidl_return);