Merge "Camera service: Fix dump() for treble path and rearrange it"
diff --git a/drm/libmediadrm/Android.mk b/drm/libmediadrm/Android.mk
index 7e77aac..14740e6 100644
--- a/drm/libmediadrm/Android.mk
+++ b/drm/libmediadrm/Android.mk
@@ -13,7 +13,7 @@
     IDrmClient.cpp \
     IMediaDrmService.cpp \
     SharedLibrary.cpp
-ifeq ($(ENABLE_TREBLE_DRM), true)
+ifeq ($(ENABLE_TREBLE), true)
 LOCAL_SRC_FILES += \
     DrmHal.cpp \
     CryptoHal.cpp
@@ -31,7 +31,7 @@
     libmediautils \
     libstagefright_foundation \
     libutils
-ifeq ($(ENABLE_TREBLE_DRM), true)
+ifeq ($(ENABLE_TREBLE), true)
 LOCAL_SHARED_LIBRARIES += \
     android.hidl.base@1.0 \
     android.hardware.drm@1.0 \
diff --git a/drm/libmediadrm/Drm.cpp b/drm/libmediadrm/Drm.cpp
index 07e9414..e3176e3 100644
--- a/drm/libmediadrm/Drm.cpp
+++ b/drm/libmediadrm/Drm.cpp
@@ -303,7 +303,8 @@
     return true;
 }
 
-status_t Drm::createPlugin(const uint8_t uuid[16]) {
+status_t Drm::createPlugin(const uint8_t uuid[16],
+                           const String8& /* appPackageName */) {
     Mutex::Autolock autoLock(mLock);
 
     if (mPlugin != NULL) {
@@ -319,7 +320,12 @@
     }
 
     status_t result = mFactory->createDrmPlugin(uuid, &mPlugin);
-    mPlugin->setListener(this);
+    if (mPlugin) {
+        mPlugin->setListener(this);
+    } else {
+        ALOGE("Failed to create plugin");
+        return UNEXPECTED_NULL;
+    }
     return result;
 }
 
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 304cdaf..42dce35 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -205,21 +205,22 @@
     return factory;
 }
 
-sp<IDrmPlugin> DrmHal::makeDrmPlugin(const uint8_t uuid[16]) {
+sp<IDrmPlugin> DrmHal::makeDrmPlugin(const uint8_t uuid[16],
+        const String8& appPackageName) {
     if (mFactory == NULL){
         return NULL;
     }
 
     sp<IDrmPlugin> plugin;
-    Return<void> hResult = mFactory->createPlugin(uuid,
+    Return<void> hResult = mFactory->createPlugin(uuid, appPackageName.string(),
             [&](Status status, const sp<IDrmPlugin>& hPlugin) {
-                if (status != Status::OK) {
-                    ALOGD("Failed to make drm plugin");
-                    return;
-                }
-                plugin = hPlugin;
-            }
-        );
+      if (status != Status::OK) {
+        ALOGD("Failed to make drm plugin");
+        return;
+      }
+      plugin = hPlugin;
+    }
+    );
     return plugin;
 }
 
@@ -350,10 +351,11 @@
     return result;
 }
 
-status_t DrmHal::createPlugin(const uint8_t uuid[16]) {
+status_t DrmHal::createPlugin(const uint8_t uuid[16],
+        const String8& appPackageName) {
     Mutex::Autolock autoLock(mLock);
 
-    mPlugin = makeDrmPlugin(uuid);
+    mPlugin = makeDrmPlugin(uuid, appPackageName);
 
     if (mPlugin == NULL) {
         mInitCheck = ERROR_UNSUPPORTED;
@@ -597,8 +599,7 @@
 }
 
 status_t DrmHal::provideProvisionResponse(Vector<uint8_t> const &response,
-                                       Vector<uint8_t> &certificate,
-                                       Vector<uint8_t> &wrappedKey) {
+        Vector<uint8_t> &certificate, Vector<uint8_t> &wrappedKey) {
     Mutex::Autolock autoLock(mLock);
 
     if (mInitCheck != OK) {
@@ -783,10 +784,8 @@
 }
 
 status_t DrmHal::encrypt(Vector<uint8_t> const &sessionId,
-                      Vector<uint8_t> const &keyId,
-                      Vector<uint8_t> const &input,
-                      Vector<uint8_t> const &iv,
-                      Vector<uint8_t> &output) {
+        Vector<uint8_t> const &keyId, Vector<uint8_t> const &input,
+        Vector<uint8_t> const &iv, Vector<uint8_t> &output) {
     Mutex::Autolock autoLock(mLock);
 
     if (mInitCheck != OK) {
@@ -811,10 +810,8 @@
 }
 
 status_t DrmHal::decrypt(Vector<uint8_t> const &sessionId,
-                      Vector<uint8_t> const &keyId,
-                      Vector<uint8_t> const &input,
-                      Vector<uint8_t> const &iv,
-                      Vector<uint8_t> &output) {
+        Vector<uint8_t> const &keyId, Vector<uint8_t> const &input,
+        Vector<uint8_t> const &iv, Vector<uint8_t> &output) {
     Mutex::Autolock autoLock(mLock);
 
     if (mInitCheck != OK) {
@@ -839,9 +836,8 @@
 }
 
 status_t DrmHal::sign(Vector<uint8_t> const &sessionId,
-                   Vector<uint8_t> const &keyId,
-                   Vector<uint8_t> const &message,
-                   Vector<uint8_t> &signature) {
+        Vector<uint8_t> const &keyId, Vector<uint8_t> const &message,
+        Vector<uint8_t> &signature) {
     Mutex::Autolock autoLock(mLock);
 
     if (mInitCheck != OK) {
@@ -866,10 +862,8 @@
 }
 
 status_t DrmHal::verify(Vector<uint8_t> const &sessionId,
-                     Vector<uint8_t> const &keyId,
-                     Vector<uint8_t> const &message,
-                     Vector<uint8_t> const &signature,
-                     bool &match) {
+        Vector<uint8_t> const &keyId, Vector<uint8_t> const &message,
+        Vector<uint8_t> const &signature, bool &match) {
     Mutex::Autolock autoLock(mLock);
 
     if (mInitCheck != OK) {
@@ -896,10 +890,8 @@
 }
 
 status_t DrmHal::signRSA(Vector<uint8_t> const &sessionId,
-                      String8 const &algorithm,
-                      Vector<uint8_t> const &message,
-                      Vector<uint8_t> const &wrappedKey,
-                      Vector<uint8_t> &signature) {
+        String8 const &algorithm, Vector<uint8_t> const &message,
+        Vector<uint8_t> const &wrappedKey, Vector<uint8_t> &signature) {
     Mutex::Autolock autoLock(mLock);
 
     if (mInitCheck != OK) {
diff --git a/drm/libmediadrm/IDrm.cpp b/drm/libmediadrm/IDrm.cpp
index c4558c6..4e47112 100644
--- a/drm/libmediadrm/IDrm.cpp
+++ b/drm/libmediadrm/IDrm.cpp
@@ -88,13 +88,15 @@
         return reply.readInt32() != 0;
     }
 
-    virtual status_t createPlugin(const uint8_t uuid[16]) {
+    virtual status_t createPlugin(const uint8_t uuid[16],
+                                  const String8& appPackageName) {
         Parcel data, reply;
         data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
         data.write(uuid, 16);
-
+        data.writeString8(appPackageName);
         status_t status = remote()->transact(CREATE_PLUGIN, data, &reply);
         if (status != OK) {
+            ALOGE("createPlugin: binder call failed: %d", status);
             return status;
         }
 
@@ -585,7 +587,6 @@
             data.read(uuid, sizeof(uuid));
             String8 mimeType = data.readString8();
             reply->writeInt32(isCryptoSchemeSupported(uuid, mimeType));
-
             return OK;
         }
 
@@ -594,7 +595,8 @@
             CHECK_INTERFACE(IDrm, data, reply);
             uint8_t uuid[16];
             data.read(uuid, sizeof(uuid));
-            reply->writeInt32(createPlugin(uuid));
+            String8 appPackageName = data.readString8();
+            reply->writeInt32(createPlugin(uuid, appPackageName));
             return OK;
         }
 
diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.cpp b/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
index d27956c..c83321b 100644
--- a/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
+++ b/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
@@ -44,7 +44,8 @@
 }
 
 android::status_t DrmFactory::createDrmPlugin(
-        const uint8_t uuid[16], android::DrmPlugin** plugin) {
+        const uint8_t uuid[16],
+        android::DrmPlugin** plugin) {
     if (!isCryptoSchemeSupported(uuid)) {
         *plugin = NULL;
         return android::BAD_VALUE;
diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.h b/drm/mediadrm/plugins/clearkey/DrmFactory.h
index 87db982..0bc0843 100644
--- a/drm/mediadrm/plugins/clearkey/DrmFactory.h
+++ b/drm/mediadrm/plugins/clearkey/DrmFactory.h
@@ -35,7 +35,8 @@
     virtual bool isContentTypeSupported(const android::String8 &mimeType);
 
     virtual android::status_t createDrmPlugin(
-            const uint8_t uuid[16], android::DrmPlugin** plugin);
+            const uint8_t uuid[16],
+            android::DrmPlugin** plugin);
 
 private:
     DISALLOW_EVIL_CONSTRUCTORS(DrmFactory);
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
index a38cca9..c82b9d9 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
@@ -56,7 +56,8 @@
         return true;
     }
 
-    status_t MockDrmFactory::createDrmPlugin(const uint8_t /* uuid */[16], DrmPlugin **plugin)
+    status_t MockDrmFactory::createDrmPlugin(const uint8_t /* uuid */[16],
+                                             DrmPlugin **plugin)
     {
         *plugin = new MockDrmPlugin();
         return OK;
@@ -729,7 +730,7 @@
 
     ssize_t MockDrmPlugin::findSession(Vector<uint8_t> const &sessionId) const
     {
-        ALOGD("findSession: nsessions=%d, size=%d", mSessions.size(), sessionId.size());
+        ALOGD("findSession: nsessions=%u, size=%u", mSessions.size(), sessionId.size());
         for (size_t i = 0; i < mSessions.size(); ++i) {
             if (memcmp(mSessions[i].array(), sessionId.array(), sessionId.size()) == 0) {
                 return i;
@@ -740,7 +741,7 @@
 
     ssize_t MockDrmPlugin::findKeySet(Vector<uint8_t> const &keySetId) const
     {
-        ALOGD("findKeySet: nkeySets=%d, size=%d", mKeySets.size(), keySetId.size());
+        ALOGD("findKeySet: nkeySets=%u, size=%u", mKeySets.size(), keySetId.size());
         for (size_t i = 0; i < mKeySets.size(); ++i) {
             if (memcmp(mKeySets[i].array(), keySetId.array(), keySetId.size()) == 0) {
                 return i;
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
index 98bdd69..9f8db17 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
@@ -33,7 +33,8 @@
 
         bool isCryptoSchemeSupported(const uint8_t uuid[16]);
         bool isContentTypeSupported(const String8 &mimeType);
-        status_t createDrmPlugin(const uint8_t uuid[16], DrmPlugin **plugin);
+        status_t createDrmPlugin(const uint8_t uuid[16],
+                                 DrmPlugin **plugin);
     };
 
     class MockCryptoFactory : public CryptoFactory {
diff --git a/include/media/Drm.h b/include/media/Drm.h
index d40019b..fc869cc 100644
--- a/include/media/Drm.h
+++ b/include/media/Drm.h
@@ -40,7 +40,7 @@
 
     virtual bool isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType);
 
-    virtual status_t createPlugin(const uint8_t uuid[16]);
+    virtual status_t createPlugin(const uint8_t uuid[16], const String8 &appPackageName);
 
     virtual status_t destroyPlugin();
 
diff --git a/include/media/DrmHal.h b/include/media/DrmHal.h
index aaea2c9..82d2555 100644
--- a/include/media/DrmHal.h
+++ b/include/media/DrmHal.h
@@ -49,7 +49,8 @@
 
     virtual bool isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType);
 
-    virtual status_t createPlugin(const uint8_t uuid[16]);
+    virtual status_t createPlugin(const uint8_t uuid[16],
+                                  const String8 &appPackageName);
 
     virtual status_t destroyPlugin();
 
@@ -169,7 +170,8 @@
     status_t mInitCheck;
 
     sp<IDrmFactory> makeDrmFactory();
-    sp<IDrmPlugin> makeDrmPlugin(const uint8_t uuid[16]);
+    sp<IDrmPlugin> makeDrmPlugin(const uint8_t uuid[16],
+                                 const String8 &appPackageName);
 
     void writeByteArray(Parcel &obj, const hidl_vec<uint8_t>& array);
 
diff --git a/include/media/IDrm.h b/include/media/IDrm.h
index fd51fd0..a57e372 100644
--- a/include/media/IDrm.h
+++ b/include/media/IDrm.h
@@ -34,7 +34,8 @@
 
     virtual bool isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) = 0;
 
-    virtual status_t createPlugin(const uint8_t uuid[16]) = 0;
+    virtual status_t createPlugin(const uint8_t uuid[16],
+                                  const String8 &appPackageName) = 0;
 
     virtual status_t destroyPlugin() = 0;
 
diff --git a/include/media/stagefright/OMXClient.h b/include/media/stagefright/OMXClient.h
index 6973405..6b86cbf 100644
--- a/include/media/stagefright/OMXClient.h
+++ b/include/media/stagefright/OMXClient.h
@@ -27,6 +27,7 @@
     OMXClient();
 
     status_t connect();
+    status_t connectTreble();
     void disconnect();
 
     sp<IOMX> interface() {
diff --git a/media/libaudiohal/EffectBufferHalLocal.cpp b/media/libaudiohal/EffectBufferHalLocal.cpp
index 7e6ee85..9fe2c7b 100644
--- a/media/libaudiohal/EffectBufferHalLocal.cpp
+++ b/media/libaudiohal/EffectBufferHalLocal.cpp
@@ -75,10 +75,10 @@
 void EffectBufferHalLocal::commit() {
 }
 
-void EffectBufferHalLocal::update(size_t size) {
+void EffectBufferHalLocal::update(size_t) {
 }
 
-void EffectBufferHalLocal::commit(size_t size) {
+void EffectBufferHalLocal::commit(size_t) {
 }
 
 } // namespace android
diff --git a/media/libaudiohal/EffectsFactoryHalHidl.cpp b/media/libaudiohal/EffectsFactoryHalHidl.cpp
index 1ab5dad..ad12654 100644
--- a/media/libaudiohal/EffectsFactoryHalHidl.cpp
+++ b/media/libaudiohal/EffectsFactoryHalHidl.cpp
@@ -17,7 +17,9 @@
 #define LOG_TAG "EffectsFactoryHalHidl"
 //#define LOG_NDEBUG 0
 
+#include <android/hidl/memory/1.0/IAllocator.h>
 #include <cutils/native_handle.h>
+#include <hidl/ServiceManagement.h>
 #include <media/EffectsFactoryApi.h>
 
 #include "ConversionHelperHidl.h"
@@ -45,6 +47,10 @@
 
 EffectsFactoryHalHidl::EffectsFactoryHalHidl() : ConversionHelperHidl("EffectsFactory"){
     mEffectsFactory = IEffectsFactory::getService("audio_effects_factory");
+    // TODO: Waiting should not be needed (b/34772726).
+    // Also remove include of IAllocator.h and ServiceManagement.h
+    android::hardware::details::waitForHwService(
+            hidl::memory::V1_0::IAllocator::descriptor, "ashmem");
 }
 
 EffectsFactoryHalHidl::~EffectsFactoryHalHidl() {
diff --git a/media/libmedia/TypeConverter.cpp b/media/libmedia/TypeConverter.cpp
index 25c29f2..8ce2b9f 100644
--- a/media/libmedia/TypeConverter.cpp
+++ b/media/libmedia/TypeConverter.cpp
@@ -186,6 +186,7 @@
     MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_SBC),
     MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APTX),
     MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APTX_HD),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AC4),
     MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_LDAC),
     TERMINATOR
 };
@@ -211,6 +212,7 @@
     MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_MONO),
     MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_STEREO),
     MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
+    MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_6),
     MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO),
     MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO),
     MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_VOICE_CALL_MONO),
diff --git a/media/liboboe/examples/write_sine/src/write_sine_threaded.cpp b/media/liboboe/examples/write_sine/src/write_sine_threaded.cpp
index aedcc6e..66f018b 100644
--- a/media/liboboe/examples/write_sine/src/write_sine_threaded.cpp
+++ b/media/liboboe/examples/write_sine/src/write_sine_threaded.cpp
@@ -27,6 +27,7 @@
 #include "SineGenerator.h"
 
 #define NUM_SECONDS   10
+
 #define SHARING_MODE  OBOE_SHARING_MODE_EXCLUSIVE
 //#define SHARING_MODE  OBOE_SHARING_MODE_LEGACY
 
@@ -133,15 +134,18 @@
     }
 
     oboe_result_t close() {
-        stop();
-        OboeStream_close(mStream);
-        mStream = OBOE_HANDLE_INVALID;
-        OboeStreamBuilder_delete(mBuilder);
-        mBuilder = OBOE_HANDLE_INVALID;
-        delete mOutputBuffer;
-        mOutputBuffer = nullptr;
-        delete mConversionBuffer;
-        mConversionBuffer = nullptr;
+        if (mStream != OBOE_HANDLE_INVALID) {
+            stop();
+            printf("call OboeStream_close(0x%08x)\n", mStream);  fflush(stdout);
+            OboeStream_close(mStream);
+            mStream = OBOE_HANDLE_INVALID;
+            OboeStreamBuilder_delete(mBuilder);
+            mBuilder = OBOE_HANDLE_INVALID;
+            delete mOutputBuffer;
+            mOutputBuffer = nullptr;
+            delete mConversionBuffer;
+            mConversionBuffer = nullptr;
+        }
         return OBOE_OK;
     }
 
@@ -274,9 +278,9 @@
     printf("player.getFramesPerSecond() = %d\n", player.getFramesPerSecond());
     printf("player.getSamplesPerFrame() = %d\n", player.getSamplesPerFrame());
     myData.sineOsc1.setup(440.0, 48000);
-    myData.sineOsc1.setSweep(300.0, 2000.0, 5.0);
+    myData.sineOsc1.setSweep(300.0, 600.0, 5.0);
     myData.sineOsc2.setup(660.0, 48000);
-    myData.sineOsc2.setSweep(400.0, 3000.0, 7.0);
+    myData.sineOsc2.setSweep(350.0, 900.0, 7.0);
     myData.samplesPerFrame = player.getSamplesPerFrame();
 
     result = player.start();
diff --git a/media/liboboe/include/oboe/OboeAudio.h b/media/liboboe/include/oboe/OboeAudio.h
index 52e3f69..7ad354c 100644
--- a/media/liboboe/include/oboe/OboeAudio.h
+++ b/media/liboboe/include/oboe/OboeAudio.h
@@ -154,7 +154,7 @@
 
 
 /**
- * Request a sample data format, for example OBOE_AUDIO_FORMAT_PCM16.
+ * Request a sample data format, for example OBOE_AUDIO_FORMAT_PCM_I16.
  * The application should query for the actual format after the stream is opened.
  *
  * @return OBOE_OK or a negative error.
diff --git a/media/liboboe/include/oboe/OboeDefinitions.h b/media/liboboe/include/oboe/OboeDefinitions.h
index 9d56a24..9ad7387 100644
--- a/media/liboboe/include/oboe/OboeDefinitions.h
+++ b/media/liboboe/include/oboe/OboeDefinitions.h
@@ -67,12 +67,17 @@
 enum oboe_audio_format_t {
     OBOE_AUDIO_FORMAT_INVALID = -1,
     OBOE_AUDIO_FORMAT_UNSPECIFIED = 0,
-    OBOE_AUDIO_FORMAT_PCM16, // TODO rename to _PCM_I16
+    OBOE_AUDIO_FORMAT_PCM_I16,
     OBOE_AUDIO_FORMAT_PCM_FLOAT,
-    OBOE_AUDIO_FORMAT_PCM824, // TODO rename to _PCM_I8_24
-    OBOE_AUDIO_FORMAT_PCM32  // TODO rename to _PCM_I32
+    OBOE_AUDIO_FORMAT_PCM_I8_24,
+    OBOE_AUDIO_FORMAT_PCM_I32
 };
 
+// TODO These are deprecated. Remove these aliases once all references are replaced.
+#define OBOE_AUDIO_FORMAT_PCM16    OBOE_AUDIO_FORMAT_PCM_I16
+#define OBOE_AUDIO_FORMAT_PCM824   OBOE_AUDIO_FORMAT_PCM_I8_24
+#define OBOE_AUDIO_FORMAT_PCM32    OBOE_AUDIO_FORMAT_PCM_I32
+
 enum {
     OBOE_OK,
     OBOE_ERROR_BASE = -900, // TODO review
@@ -93,7 +98,8 @@
     OBOE_ERROR_TIMEOUT,
     OBOE_ERROR_WOULD_BLOCK,
     OBOE_ERROR_INVALID_ORDER,
-    OBOE_ERROR_OUT_OF_RANGE
+    OBOE_ERROR_OUT_OF_RANGE,
+    OBOE_ERROR_NO_SERVICE
 };
 
 typedef enum {
diff --git a/media/liboboe/src/binding/IOboeAudioService.cpp b/media/liboboe/src/binding/IOboeAudioService.cpp
index a3437b2..2584bc9 100644
--- a/media/liboboe/src/binding/IOboeAudioService.cpp
+++ b/media/liboboe/src/binding/IOboeAudioService.cpp
@@ -20,6 +20,7 @@
 #include "binding/OboeStreamRequest.h"
 #include "binding/OboeStreamConfiguration.h"
 #include "binding/IOboeAudioService.h"
+#include "utility/OboeUtilities.h"
 
 namespace android {
 
@@ -44,7 +45,7 @@
         request.writeToParcel(&data);
         status_t err = remote()->transact(OPEN_STREAM, data, &reply);
         if (err != NO_ERROR) {
-            return OBOE_ERROR_INTERNAL; // TODO consider another error
+            return OboeConvert_androidToOboeResult(err);
         }
         // parse reply
         oboe_handle_t stream;
@@ -53,14 +54,14 @@
         return stream;
     }
 
-    virtual oboe_result_t closeStream(int32_t streamHandle) override {
+    virtual oboe_result_t closeStream(oboe_handle_t streamHandle) override {
         Parcel data, reply;
         // send command
         data.writeInterfaceToken(IOboeAudioService::getInterfaceDescriptor());
         data.writeInt32(streamHandle);
         status_t err = remote()->transact(CLOSE_STREAM, data, &reply);
         if (err != NO_ERROR) {
-            return OBOE_ERROR_INTERNAL; // TODO consider another error
+            return OboeConvert_androidToOboeResult(err);
         }
         // parse reply
         oboe_result_t res;
@@ -69,14 +70,14 @@
     }
 
     virtual oboe_result_t getStreamDescription(oboe_handle_t streamHandle,
-                                               AudioEndpointParcelable &parcelable)   {
+                                               oboe::AudioEndpointParcelable &parcelable)   {
         Parcel data, reply;
         // send command
         data.writeInterfaceToken(IOboeAudioService::getInterfaceDescriptor());
         data.writeInt32(streamHandle);
         status_t err = remote()->transact(GET_STREAM_DESCRIPTION, data, &reply);
         if (err != NO_ERROR) {
-            return OBOE_ERROR_INTERNAL; // TODO consider another error
+            return OboeConvert_androidToOboeResult(err);
         }
         // parse reply
         parcelable.readFromParcel(&reply);
@@ -97,7 +98,7 @@
         data.writeInt32(streamHandle);
         status_t err = remote()->transact(START_STREAM, data, &reply);
         if (err != NO_ERROR) {
-            return OBOE_ERROR_INTERNAL; // TODO consider another error
+            return OboeConvert_androidToOboeResult(err);
         }
         // parse reply
         oboe_result_t res;
@@ -112,7 +113,7 @@
         data.writeInt32(streamHandle);
         status_t err = remote()->transact(PAUSE_STREAM, data, &reply);
         if (err != NO_ERROR) {
-            return OBOE_ERROR_INTERNAL; // TODO consider another error
+            return OboeConvert_androidToOboeResult(err);
         }
         // parse reply
         oboe_result_t res;
@@ -127,7 +128,7 @@
         data.writeInt32(streamHandle);
         status_t err = remote()->transact(FLUSH_STREAM, data, &reply);
         if (err != NO_ERROR) {
-            return OBOE_ERROR_INTERNAL; // TODO consider another error
+            return OboeConvert_androidToOboeResult(err);
         }
         // parse reply
         oboe_result_t res;
@@ -135,13 +136,6 @@
         return res;
     }
 
-    virtual void tickle() override { // TODO remove after service thread implemented
-        Parcel data;
-        // send command
-        data.writeInterfaceToken(IOboeAudioService::getInterfaceDescriptor());
-        remote()->transact(TICKLE, data, nullptr);
-    }
-
     virtual oboe_result_t registerAudioThread(oboe_handle_t streamHandle, pid_t clientThreadId,
                                               oboe_nanoseconds_t periodNanoseconds)
     override {
@@ -153,7 +147,7 @@
         data.writeInt64(periodNanoseconds);
         status_t err = remote()->transact(REGISTER_AUDIO_THREAD, data, &reply);
         if (err != NO_ERROR) {
-            return OBOE_ERROR_INTERNAL; // TODO consider another error
+            return OboeConvert_androidToOboeResult(err);
         }
         // parse reply
         oboe_result_t res;
@@ -170,7 +164,7 @@
         data.writeInt32((int32_t) clientThreadId);
         status_t err = remote()->transact(UNREGISTER_AUDIO_THREAD, data, &reply);
         if (err != NO_ERROR) {
-            return OBOE_ERROR_INTERNAL; // TODO consider another error
+            return OboeConvert_androidToOboeResult(err);
         }
         // parse reply
         oboe_result_t res;
@@ -189,8 +183,8 @@
 status_t BnOboeAudioService::onTransact(uint32_t code, const Parcel& data,
                                         Parcel* reply, uint32_t flags) {
     OboeStream stream;
-    OboeStreamRequest request;
-    OboeStreamConfiguration configuration;
+    oboe::OboeStreamRequest request;
+    oboe::OboeStreamConfiguration configuration;
     pid_t pid;
     oboe_nanoseconds_t nanoseconds;
     oboe_result_t result;
@@ -201,7 +195,7 @@
         case OPEN_STREAM: {
             request.readFromParcel(&data);
             stream = openStream(request, configuration);
-            ALOGD("BnOboeAudioService::onTransact OPEN_STREAM 0x%08X", stream);
+            ALOGD("BnOboeAudioService::onTransact OPEN_STREAM server handle = 0x%08X", stream);
             reply->writeInt32(stream);
             configuration.writeToParcel(reply);
             return NO_ERROR;
@@ -221,12 +215,12 @@
             oboe::AudioEndpointParcelable parcelable;
             result = getStreamDescription(stream, parcelable);
             if (result != OBOE_OK) {
-                return -1; // FIXME
+                return OboeConvert_oboeToAndroidStatus(result);
             }
             parcelable.dump();
             result = parcelable.validate();
             if (result != OBOE_OK) {
-                return -1; // FIXME
+                return OboeConvert_oboeToAndroidStatus(result);
             }
             parcelable.writeToParcel(reply);
             reply->writeInt32(result);
@@ -281,12 +275,6 @@
             return NO_ERROR;
         } break;
 
-        case TICKLE: {
-            ALOGV("BnOboeAudioService::onTransact TICKLE");
-            tickle();
-            return NO_ERROR;
-        } break;
-
         default:
             // ALOGW("BnOboeAudioService::onTransact not handled %u", code);
             return BBinder::onTransact(code, data, reply, flags);
diff --git a/media/liboboe/src/binding/IOboeAudioService.h b/media/liboboe/src/binding/IOboeAudioService.h
index 4b4c99c..e2a9c15 100644
--- a/media/liboboe/src/binding/IOboeAudioService.h
+++ b/media/liboboe/src/binding/IOboeAudioService.h
@@ -29,13 +29,6 @@
 #include "binding/OboeStreamRequest.h"
 #include "binding/OboeStreamConfiguration.h"
 
-//using android::status_t;
-//using android::IInterface;
-//using android::BnInterface;
-
-using oboe::AudioEndpointParcelable;
-using oboe::OboeStreamRequest;
-using oboe::OboeStreamConfiguration;
 
 namespace android {
 
@@ -45,16 +38,16 @@
 
     DECLARE_META_INTERFACE(OboeAudioService);
 
-    virtual oboe_handle_t openStream(OboeStreamRequest &request,
-                                     OboeStreamConfiguration &configuration) = 0;
+    virtual oboe_handle_t openStream(oboe::OboeStreamRequest &request,
+                                     oboe::OboeStreamConfiguration &configuration) = 0;
 
-    virtual oboe_result_t closeStream(int32_t streamHandle) = 0;
+    virtual oboe_result_t closeStream(oboe_handle_t streamHandle) = 0;
 
     /* Get an immutable description of the in-memory queues
     * used to communicate with the underlying HAL or Service.
     */
     virtual oboe_result_t getStreamDescription(oboe_handle_t streamHandle,
-                                               AudioEndpointParcelable &parcelable) = 0;
+                                               oboe::AudioEndpointParcelable &parcelable) = 0;
 
     /**
      * Start the flow of data.
@@ -79,14 +72,6 @@
 
     virtual oboe_result_t unregisterAudioThread(oboe_handle_t streamHandle,
                                                 pid_t clientThreadId) = 0;
-
-    /**
-     * Poke server instead of running a background thread.
-     * Cooperative multi-tasking for early development only.
-     * TODO remove tickle() when service has its own thread.
-     */
-    virtual void tickle() { };
-
 };
 
 class BnOboeAudioService : public BnInterface<IOboeAudioService> {
diff --git a/media/liboboe/src/binding/OboeServiceDefinitions.h b/media/liboboe/src/binding/OboeServiceDefinitions.h
index ad00fe2..33a192f 100644
--- a/media/liboboe/src/binding/OboeServiceDefinitions.h
+++ b/media/liboboe/src/binding/OboeServiceDefinitions.h
@@ -37,8 +37,7 @@
     PAUSE_STREAM,
     FLUSH_STREAM,
     REGISTER_AUDIO_THREAD,
-    UNREGISTER_AUDIO_THREAD,
-    TICKLE
+    UNREGISTER_AUDIO_THREAD
 };
 
 } // namespace android
@@ -53,8 +52,7 @@
     PAUSE_STREAM,
     FLUSH_STREAM,
     REGISTER_AUDIO_THREAD,
-    UNREGISTER_AUDIO_THREAD,
-    TICKLE
+    UNREGISTER_AUDIO_THREAD
 };
 
 // TODO Expand this to include all the open parameters.
diff --git a/media/liboboe/src/binding/OboeStreamConfiguration.cpp b/media/liboboe/src/binding/OboeStreamConfiguration.cpp
index 4b8b5b2..124e964 100644
--- a/media/liboboe/src/binding/OboeStreamConfiguration.cpp
+++ b/media/liboboe/src/binding/OboeStreamConfiguration.cpp
@@ -65,10 +65,10 @@
     }
 
     switch (mAudioFormat) {
-    case OBOE_AUDIO_FORMAT_PCM16:
+    case OBOE_AUDIO_FORMAT_PCM_I16:
     case OBOE_AUDIO_FORMAT_PCM_FLOAT:
-    case OBOE_AUDIO_FORMAT_PCM824:
-    case OBOE_AUDIO_FORMAT_PCM32:
+    case OBOE_AUDIO_FORMAT_PCM_I8_24:
+    case OBOE_AUDIO_FORMAT_PCM_I32:
         break;
     default:
         ALOGE("OboeStreamConfiguration.validate() invalid audioFormat = %d", mAudioFormat);
diff --git a/media/liboboe/src/client/AudioStreamInternal.cpp b/media/liboboe/src/client/AudioStreamInternal.cpp
index 0d169e1..dc6fe90 100644
--- a/media/liboboe/src/client/AudioStreamInternal.cpp
+++ b/media/liboboe/src/client/AudioStreamInternal.cpp
@@ -22,6 +22,7 @@
 #include <assert.h>
 
 #include <binder/IServiceManager.h>
+#include <utils/Mutex.h>
 
 #include <oboe/OboeAudio.h>
 
@@ -40,16 +41,40 @@
 using android::IServiceManager;
 using android::defaultServiceManager;
 using android::interface_cast;
+using android::Mutex;
 
 using namespace oboe;
 
+static android::Mutex gServiceLock;
+static sp<IOboeAudioService>  gOboeService;
+
+#define OBOE_SERVICE_NAME   "OboeAudioService"
+
 // Helper function to get access to the "OboeAudioService" service.
-static sp<IOboeAudioService> getOboeAudioService() {
-    sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> binder = sm->getService(String16("OboeAudioService"));
-    // TODO: If the "OboeHack" service is not running, getService times out and binder == 0.
-    sp<IOboeAudioService> service = interface_cast<IOboeAudioService>(binder);
-    return service;
+// This code was modeled after frameworks/av/media/libaudioclient/AudioSystem.cpp
+static const sp<IOboeAudioService> getOboeAudioService() {
+    sp<IBinder> binder;
+    Mutex::Autolock _l(gServiceLock);
+    if (gOboeService == 0) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        // Try several times to get the service.
+        int retries = 4;
+        do {
+            binder = sm->getService(String16(OBOE_SERVICE_NAME)); // This will wait a while.
+            if (binder != 0) {
+                break;
+            }
+        } while (retries-- > 0);
+
+        if (binder != 0) {
+            // TODO Add linkToDeath() like in frameworks/av/media/libaudioclient/AudioSystem.cpp
+            // TODO Create a DeathRecipient that disconnects all active streams.
+            gOboeService = interface_cast<IOboeAudioService>(binder);
+        } else {
+            ALOGE("AudioStreamInternal could not get %s", OBOE_SERVICE_NAME);
+        }
+    }
+    return gOboeService;
 }
 
 AudioStreamInternal::AudioStreamInternal()
@@ -59,9 +84,6 @@
         , mServiceStreamHandle(OBOE_HANDLE_INVALID)
         , mFramesPerBurst(16)
 {
-    // TODO protect against mService being NULL;
-    // TODO Model access to the service on frameworks/av/media/libaudioclient/AudioSystem.cpp
-    mService = getOboeAudioService();
 }
 
 AudioStreamInternal::~AudioStreamInternal() {
@@ -69,6 +91,9 @@
 
 oboe_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) {
 
+    const sp<IOboeAudioService>& service = getOboeAudioService();
+    if (service == 0) return OBOE_ERROR_NO_SERVICE;
+
     oboe_result_t result = OBOE_OK;
     OboeStreamRequest request;
     OboeStreamConfiguration configuration;
@@ -78,7 +103,7 @@
         return result;
     }
 
-    // Build the request.
+    // Build the request to send to the server.
     request.setUserId(getuid());
     request.setProcessId(getpid());
     request.getConfiguration().setDeviceId(getDeviceId());
@@ -87,7 +112,7 @@
     request.getConfiguration().setAudioFormat(getFormat());
     request.dump();
 
-    mServiceStreamHandle = mService->openStream(request, configuration);
+    mServiceStreamHandle = service->openStream(request, configuration);
     ALOGD("AudioStreamInternal.open(): openStream returned mServiceStreamHandle = 0x%08X",
          (unsigned int)mServiceStreamHandle);
     if (mServiceStreamHandle < 0) {
@@ -105,10 +130,10 @@
         setFormat(configuration.getAudioFormat());
 
         oboe::AudioEndpointParcelable parcelable;
-        result = mService->getStreamDescription(mServiceStreamHandle, parcelable);
+        result = service->getStreamDescription(mServiceStreamHandle, parcelable);
         if (result != OBOE_OK) {
             ALOGE("AudioStreamInternal.open(): getStreamDescriptor returns %d", result);
-            mService->closeStream(mServiceStreamHandle);
+            service->closeStream(mServiceStreamHandle);
             return result;
         }
         // resolve parcelable into a descriptor
@@ -133,11 +158,14 @@
 oboe_result_t AudioStreamInternal::close() {
     ALOGD("AudioStreamInternal.close(): mServiceStreamHandle = 0x%08X", mServiceStreamHandle);
     if (mServiceStreamHandle != OBOE_HANDLE_INVALID) {
-        mService->closeStream(mServiceStreamHandle);
+        oboe_handle_t serviceStreamHandle = mServiceStreamHandle;
         mServiceStreamHandle = OBOE_HANDLE_INVALID;
+        const sp<IOboeAudioService>& oboeService = getOboeAudioService();
+        if (oboeService == 0) return OBOE_ERROR_NO_SERVICE;
+        oboeService->closeStream(serviceStreamHandle);
         return OBOE_OK;
     } else {
-        return OBOE_ERROR_INVALID_STATE;
+        return OBOE_ERROR_INVALID_HANDLE;
     }
 }
 
@@ -148,11 +176,13 @@
     if (mServiceStreamHandle == OBOE_HANDLE_INVALID) {
         return OBOE_ERROR_INVALID_STATE;
     }
+    const sp<IOboeAudioService>& oboeService = getOboeAudioService();
+    if (oboeService == 0) return OBOE_ERROR_NO_SERVICE;
     startTime = Oboe_getNanoseconds(OBOE_CLOCK_MONOTONIC);
     mClockModel.start(startTime);
     processTimestamp(0, startTime);
     setState(OBOE_STREAM_STATE_STARTING);
-    return mService->startStream(mServiceStreamHandle);
+    return oboeService->startStream(mServiceStreamHandle);
 }
 
 oboe_result_t AudioStreamInternal::requestPause()
@@ -161,9 +191,11 @@
     if (mServiceStreamHandle == OBOE_HANDLE_INVALID) {
         return OBOE_ERROR_INVALID_STATE;
     }
+    const sp<IOboeAudioService>& oboeService = getOboeAudioService();
+    if (oboeService == 0) return OBOE_ERROR_NO_SERVICE;
     mClockModel.stop(Oboe_getNanoseconds(OBOE_CLOCK_MONOTONIC));
     setState(OBOE_STREAM_STATE_PAUSING);
-    return mService->pauseStream(mServiceStreamHandle);
+    return oboeService->pauseStream(mServiceStreamHandle);
 }
 
 oboe_result_t AudioStreamInternal::requestFlush() {
@@ -171,8 +203,10 @@
     if (mServiceStreamHandle == OBOE_HANDLE_INVALID) {
         return OBOE_ERROR_INVALID_STATE;
     }
-    setState(OBOE_STREAM_STATE_FLUSHING);
-    return mService->flushStream(mServiceStreamHandle);
+    const sp<IOboeAudioService>& oboeService = getOboeAudioService();
+    if (oboeService == 0) return OBOE_ERROR_NO_SERVICE;
+setState(OBOE_STREAM_STATE_FLUSHING);
+    return oboeService->flushStream(mServiceStreamHandle);
 }
 
 void AudioStreamInternal::onFlushFromServer() {
@@ -208,7 +242,9 @@
     if (mServiceStreamHandle == OBOE_HANDLE_INVALID) {
         return OBOE_ERROR_INVALID_STATE;
     }
-    return mService->registerAudioThread(mServiceStreamHandle,
+    const sp<IOboeAudioService>& oboeService = getOboeAudioService();
+    if (oboeService == 0) return OBOE_ERROR_NO_SERVICE;
+    return oboeService->registerAudioThread(mServiceStreamHandle,
                                          gettid(),
                                          getPeriodNanoseconds());
 }
@@ -218,7 +254,9 @@
     if (mServiceStreamHandle == OBOE_HANDLE_INVALID) {
         return OBOE_ERROR_INVALID_STATE;
     }
-    return mService->unregisterAudioThread(mServiceStreamHandle, gettid());
+    const sp<IOboeAudioService>& oboeService = getOboeAudioService();
+    if (oboeService == 0) return OBOE_ERROR_NO_SERVICE;
+    return oboeService->unregisterAudioThread(mServiceStreamHandle, gettid());
 }
 
 // TODO use oboe_clockid_t all the way down to AudioClock
@@ -305,9 +343,6 @@
 oboe_result_t AudioStreamInternal::processCommands() {
     oboe_result_t result = OBOE_OK;
 
-    // Let the service run in case it is a fake service simulator.
-    mService->tickle(); // TODO use real service thread
-
     while (result == OBOE_OK) {
         OboeServiceMessage message;
         if (mAudioEndpoint.readUpCommand(&message) != 1) {
diff --git a/media/liboboe/src/client/AudioStreamInternal.h b/media/liboboe/src/client/AudioStreamInternal.h
index 6f37761..9459f97 100644
--- a/media/liboboe/src/client/AudioStreamInternal.h
+++ b/media/liboboe/src/client/AudioStreamInternal.h
@@ -114,7 +114,6 @@
     AudioEndpoint            mAudioEndpoint;
     oboe_handle_t            mServiceStreamHandle;
     EndpointDescriptor       mEndpointDescriptor;
-    sp<IOboeAudioService>    mService;
     // Offset from underlying frame position.
     oboe_position_frames_t   mFramesOffsetFromService = 0;
     oboe_position_frames_t   mLastFramesRead = 0;
diff --git a/media/liboboe/src/core/OboeAudio.cpp b/media/liboboe/src/core/OboeAudio.cpp
index d98ca36..be563b5 100644
--- a/media/liboboe/src/core/OboeAudio.cpp
+++ b/media/liboboe/src/core/OboeAudio.cpp
@@ -96,6 +96,7 @@
         OBOE_CASE_ENUM(OBOE_ERROR_WOULD_BLOCK);
         OBOE_CASE_ENUM(OBOE_ERROR_INVALID_ORDER);
         OBOE_CASE_ENUM(OBOE_ERROR_OUT_OF_RANGE);
+        OBOE_CASE_ENUM(OBOE_ERROR_NO_SERVICE);
     }
     return "Unrecognized Oboe error.";
 }
@@ -285,7 +286,6 @@
 
 OBOE_API oboe_result_t  OboeStreamBuilder_delete(OboeStreamBuilder builder)
 {
-    // TODO protect the remove() with a Mutex
     AudioStreamBuilder *streamBuilder = (AudioStreamBuilder *)
             sHandleTracker.remove(OBOE_HANDLE_TYPE_STREAM_BUILDER, builder);
     if (streamBuilder != nullptr) {
@@ -297,9 +297,9 @@
 
 OBOE_API oboe_result_t  OboeStream_close(OboeStream stream)
 {
-    // TODO protect the remove() with a Mutex
     AudioStream *audioStream = (AudioStream *)
             sHandleTracker.remove(OBOE_HANDLE_TYPE_STREAM, (oboe_handle_t)stream);
+    ALOGD("OboeStream_close(0x%08X), audioStream = %p", stream, audioStream);
     if (audioStream != nullptr) {
         audioStream->close();
         delete audioStream;
diff --git a/media/liboboe/src/legacy/AudioStreamRecord.cpp b/media/liboboe/src/legacy/AudioStreamRecord.cpp
index 5854974..bf4bd36 100644
--- a/media/liboboe/src/legacy/AudioStreamRecord.cpp
+++ b/media/liboboe/src/legacy/AudioStreamRecord.cpp
@@ -90,7 +90,7 @@
     if (status != OK) {
         close();
         ALOGE("AudioStreamRecord::open(), initCheck() returned %d", status);
-        return OboeConvert_androidToOboeError(status);
+        return OboeConvert_androidToOboeResult(status);
     }
 
     // Get the actual rate.
@@ -121,11 +121,11 @@
     // Get current position so we can detect when the track is playing.
     status_t err = mAudioRecord->getPosition(&mPositionWhenStarting);
     if (err != OK) {
-        return OboeConvert_androidToOboeError(err);
+        return OboeConvert_androidToOboeResult(err);
     }
     err = mAudioRecord->start();
     if (err != OK) {
-        return OboeConvert_androidToOboeError(err);
+        return OboeConvert_androidToOboeResult(err);
     } else {
         setState(OBOE_STREAM_STATE_STARTING);
     }
@@ -160,7 +160,7 @@
     case OBOE_STREAM_STATE_STARTING:
         err = mAudioRecord->getPosition(&position);
         if (err != OK) {
-            result = OboeConvert_androidToOboeError(err);
+            result = OboeConvert_androidToOboeResult(err);
         } else if (position != mPositionWhenStarting) {
             setState(OBOE_STREAM_STATE_STARTED);
         }
@@ -193,7 +193,7 @@
     if (bytesRead == WOULD_BLOCK) {
         return 0;
     } else if (bytesRead < 0) {
-        return OboeConvert_androidToOboeError(bytesRead);
+        return OboeConvert_androidToOboeResult(bytesRead);
     }
     oboe_size_frames_t framesRead = (oboe_size_frames_t)(bytesRead / bytesPerFrame);
     return (oboe_result_t) framesRead;
diff --git a/media/liboboe/src/legacy/AudioStreamRecord.h b/media/liboboe/src/legacy/AudioStreamRecord.h
index 02ff220..a884ed2 100644
--- a/media/liboboe/src/legacy/AudioStreamRecord.h
+++ b/media/liboboe/src/legacy/AudioStreamRecord.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef LEGACY_AUDIOSTREAMRECORD_H
-#define LEGACY_AUDIOSTREAMRECORD_H
+#ifndef LEGACY_AUDIO_STREAM_RECORD_H
+#define LEGACY_AUDIO_STREAM_RECORD_H
 
 #include <media/AudioRecord.h>
 #include <oboe/OboeAudio.h>
@@ -75,4 +75,4 @@
 
 } /* namespace oboe */
 
-#endif /* LEGACY_AUDIOSTREAMRECORD_H */
+#endif /* LEGACY_AUDIO_STREAM_RECORD_H */
diff --git a/media/liboboe/src/legacy/AudioStreamTrack.cpp b/media/liboboe/src/legacy/AudioStreamTrack.cpp
index b2c4ee1..291e56c 100644
--- a/media/liboboe/src/legacy/AudioStreamTrack.cpp
+++ b/media/liboboe/src/legacy/AudioStreamTrack.cpp
@@ -87,12 +87,10 @@
     // Did we get a valid track?
     status_t status = mAudioTrack->initCheck();
     ALOGD("AudioStreamTrack::open(), initCheck() returned %d", status);
-    // FIXME - this should work - if (status != NO_ERROR) {
-    //         But initCheck() is returning 1 !
-    if (status < 0) {
+    if (status != NO_ERROR) {
         close();
         ALOGE("AudioStreamTrack::open(), initCheck() returned %d", status);
-        return OboeConvert_androidToOboeError(status);
+        return OboeConvert_androidToOboeResult(status);
     }
 
     // Get the actual values from the AudioTrack.
@@ -123,11 +121,11 @@
     // Get current position so we can detect when the track is playing.
     status_t err = mAudioTrack->getPosition(&mPositionWhenStarting);
     if (err != OK) {
-        return OboeConvert_androidToOboeError(err);
+        return OboeConvert_androidToOboeResult(err);
     }
     err = mAudioTrack->start();
     if (err != OK) {
-        return OboeConvert_androidToOboeError(err);
+        return OboeConvert_androidToOboeResult(err);
     } else {
         setState(OBOE_STREAM_STATE_STARTING);
     }
@@ -147,7 +145,7 @@
     mAudioTrack->pause();
     status_t err = mAudioTrack->getPosition(&mPositionWhenPausing);
     if (err != OK) {
-        return OboeConvert_androidToOboeError(err);
+        return OboeConvert_androidToOboeResult(err);
     }
     return OBOE_OK;
 }
@@ -191,7 +189,7 @@
         if (mAudioTrack->stopped()) {
             err = mAudioTrack->getPosition(&position);
             if (err != OK) {
-                return OboeConvert_androidToOboeError(err);
+                return OboeConvert_androidToOboeResult(err);
             } else if (position == mPositionWhenPausing) {
                 // Has stream really stopped advancing?
                 setState(OBOE_STREAM_STATE_PAUSED);
@@ -203,7 +201,7 @@
         {
             err = mAudioTrack->getPosition(&position);
             if (err != OK) {
-                return OboeConvert_androidToOboeError(err);
+                return OboeConvert_androidToOboeResult(err);
             } else if (position == 0) {
                 // Advance frames read to match written.
                 setState(OBOE_STREAM_STATE_FLUSHED);
@@ -239,7 +237,7 @@
         return 0;
     } else if (bytesWritten < 0) {
         ALOGE("invalid write, returned %d", (int)bytesWritten);
-        return OboeConvert_androidToOboeError(bytesWritten);
+        return OboeConvert_androidToOboeResult(bytesWritten);
     }
     oboe_size_frames_t framesWritten = (oboe_size_frames_t)(bytesWritten / bytesPerFrame);
     incrementFramesWritten(framesWritten);
@@ -251,7 +249,7 @@
 {
     ssize_t result = mAudioTrack->setBufferSizeInFrames(requestedFrames);
     if (result != OK) {
-        return OboeConvert_androidToOboeError(result);
+        return OboeConvert_androidToOboeResult(result);
     } else {
         *actualFrames = result;
         return OBOE_OK;
diff --git a/media/liboboe/src/legacy/AudioStreamTrack.h b/media/liboboe/src/legacy/AudioStreamTrack.h
index 8c40884..0c41331 100644
--- a/media/liboboe/src/legacy/AudioStreamTrack.h
+++ b/media/liboboe/src/legacy/AudioStreamTrack.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef LEGACY_AUDIOSTREAMTRACK_H
-#define LEGACY_AUDIOSTREAMTRACK_H
+#ifndef LEGACY_AUDIO_STREAM_TRACK_H
+#define LEGACY_AUDIO_STREAM_TRACK_H
 
 #include <media/AudioTrack.h>
 #include <oboe/OboeAudio.h>
@@ -75,4 +75,4 @@
 
 } /* namespace oboe */
 
-#endif /* LEGACY_AUDIOSTREAMTRACK_H */
+#endif /* LEGACY_AUDIO_STREAM_TRACK_H */
diff --git a/media/liboboe/src/utility/AudioClock.h b/media/liboboe/src/utility/AudioClock.h
index 1a5c209..1779d8b 100644
--- a/media/liboboe/src/utility/AudioClock.h
+++ b/media/liboboe/src/utility/AudioClock.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef UTILITY_AUDIOCLOCK_H
-#define UTILITY_AUDIOCLOCK_H
+#ifndef UTILITY_AUDIO_CLOCK_H
+#define UTILITY_AUDIO_CLOCK_H
 
 #include <stdint.h>
 #include <time.h>
@@ -95,4 +95,4 @@
 };
 
 
-#endif // UTILITY_AUDIOCLOCK_H
+#endif // UTILITY_AUDIO_CLOCK_H
diff --git a/media/liboboe/src/utility/HandleTracker.cpp b/media/liboboe/src/utility/HandleTracker.cpp
index bf5fb63..27cc1f8 100644
--- a/media/liboboe/src/utility/HandleTracker.cpp
+++ b/media/liboboe/src/utility/HandleTracker.cpp
@@ -19,13 +19,16 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <assert.h>
 #include <new>
 #include <stdint.h>
-#include <assert.h>
+#include <utils/Mutex.h>
 
 #include <oboe/OboeDefinitions.h>
 #include "HandleTracker.h"
 
+using android::Mutex;
+
 // Handle format is: tgggiiii
 // where each letter is 4 bits, t=type, g=generation, i=index
 
@@ -80,15 +83,17 @@
 
 HandleTracker::~HandleTracker()
 {
+    Mutex::Autolock _l(mLock);
     delete[] mHandleAddresses;
     delete[] mHandleHeaders;
+    mHandleAddresses = nullptr;
 }
 
 bool HandleTracker::isInitialized() const {
     return mHandleAddresses != nullptr;
 }
 
-handle_tracker_slot_t HandleTracker::allocateSlot() {
+handle_tracker_slot_t HandleTracker::allocateSlot_l() {
     void **allocated = mNextFreeAddress;
     if (allocated == nullptr) {
         return SLOT_UNAVAILABLE;
@@ -98,7 +103,7 @@
     return (allocated - mHandleAddresses);
 }
 
-handle_tracker_generation_t HandleTracker::nextGeneration(handle_tracker_slot_t index) {
+handle_tracker_generation_t HandleTracker::nextGeneration_l(handle_tracker_slot_t index) {
     handle_tracker_generation_t generation = (mHandleHeaders[index] + 1) & GENERATION_MASK;
     // Avoid generation zero so that 0x0 is not a valid handle.
     if (generation == GENERATION_INVALID) {
@@ -116,15 +121,17 @@
         return static_cast<oboe_handle_t>(OBOE_ERROR_NO_MEMORY);
     }
 
+    Mutex::Autolock _l(mLock);
+
     // Find an empty slot.
-    handle_tracker_slot_t index = allocateSlot();
+    handle_tracker_slot_t index = allocateSlot_l();
     if (index == SLOT_UNAVAILABLE) {
         ALOGE("HandleTracker::put() no room for more handles");
         return static_cast<oboe_handle_t>(OBOE_ERROR_NO_FREE_HANDLES);
     }
 
     // Cycle the generation counter so stale handles can be detected.
-    handle_tracker_generation_t generation = nextGeneration(index); // reads header table
+    handle_tracker_generation_t generation = nextGeneration_l(index); // reads header table
     handle_tracker_header_t inputHeader = buildHeader(type, generation);
 
     // These two writes may need to be observed by other threads or cores during get().
@@ -150,6 +157,8 @@
     }
     handle_tracker_generation_t handleGeneration = extractGeneration(handle);
     handle_tracker_header_t inputHeader = buildHeader(type, handleGeneration);
+    // We do not need to synchronize this access to mHandleHeaders because it is constant for
+    // the lifetime of the handle.
     if (inputHeader != mHandleHeaders[index]) {
         ALOGE("HandleTracker::handleToIndex() inputHeader = 0x%08x != mHandleHeaders[%d] = 0x%08x",
              inputHeader, index, mHandleHeaders[index]);
@@ -165,6 +174,8 @@
     }
     handle_tracker_slot_t index = handleToIndex(type, handle);
     if (index >= 0) {
+        // We do not need to synchronize this access to mHandleHeaders because this slot
+        // is allocated and, therefore, not part of the linked list of free slots.
         return mHandleAddresses[index];
     } else {
         return nullptr;
@@ -175,6 +186,9 @@
     if (!isInitialized()) {
         return nullptr;
     }
+
+    Mutex::Autolock _l(mLock);
+
     handle_tracker_slot_t index = handleToIndex(type,handle);
     if (index >= 0) {
         handle_tracker_address_t address = mHandleAddresses[index];
diff --git a/media/liboboe/src/utility/HandleTracker.h b/media/liboboe/src/utility/HandleTracker.h
index 4c08321..f1bead8 100644
--- a/media/liboboe/src/utility/HandleTracker.h
+++ b/media/liboboe/src/utility/HandleTracker.h
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-#ifndef UTILITY_HANDLETRACKER_H
-#define UTILITY_HANDLETRACKER_H
+#ifndef UTILITY_HANDLE_TRACKER_H
+#define UTILITY_HANDLE_TRACKER_H
 
 #include <stdint.h>
+#include <utils/Mutex.h>
 
 typedef int32_t  handle_tracker_type_t;       // what kind of handle
 typedef int32_t  handle_tracker_slot_t;       // index in allocation table
@@ -53,6 +54,8 @@
     /**
      * Store a pointer and return a handle that can be used to retrieve the pointer.
      *
+     * It is safe to call put() or remove() from multiple threads.
+     *
      * @param expectedType the type of the object to be tracked
      * @param address pointer to be converted to a handle
      * @return a valid handle or a negative error
@@ -75,6 +78,8 @@
      * Free up the storage associated with the handle.
      * Subsequent attempts to use the handle will fail.
      *
+     * Do NOT remove() a handle while get() is being called for the same handle from another thread.
+     *
      * @param expectedType shouldmatch the type we passed to put()
      * @param handle to be removed from tracking
      * @return address associated with handle or nullptr if not found
@@ -83,17 +88,28 @@
 
 private:
     const int32_t               mMaxHandleCount;   // size of array
-    // This is const after initialization.
+    // This address is const after initialization.
     handle_tracker_address_t  * mHandleAddresses;  // address of objects or a free linked list node
-    // This is const after initialization.
+    // This address is const after initialization.
     handle_tracker_header_t   * mHandleHeaders;    // combination of type and generation
-    handle_tracker_address_t  * mNextFreeAddress; // head of the linked list of free nodes in mHandleAddresses
+    // head of the linked list of free nodes in mHandleAddresses
+    handle_tracker_address_t  * mNextFreeAddress;
+
+    // This Mutex protects the linked list of free nodes.
+    // The list is managed using mHandleAddresses and mNextFreeAddress.
+    // The data in mHandleHeaders is only changed by put() and remove().
+    android::Mutex              mLock;
 
     /**
      * Pull slot off of a list of empty slots.
      * @return index or a negative error
      */
-    handle_tracker_slot_t allocateSlot();
+    handle_tracker_slot_t allocateSlot_l();
+
+    /**
+     * Increment the generation for the slot, avoiding zero.
+     */
+    handle_tracker_generation_t nextGeneration_l(handle_tracker_slot_t index);
 
     /**
      * Validate the handle and return the corresponding index.
@@ -107,7 +123,7 @@
      * @param index slot index returned from allocateSlot
      * @return handle or a negative error
      */
-    oboe_handle_t buildHandle(handle_tracker_header_t header, handle_tracker_slot_t index);
+    static oboe_handle_t buildHandle(handle_tracker_header_t header, handle_tracker_slot_t index);
 
     /**
      * Combine a type and a generation field into a header.
@@ -129,11 +145,6 @@
      */
     static handle_tracker_generation_t extractGeneration(oboe_handle_t handle);
 
-    /**
-     * Increment the generation for the slot, avoiding zero.
-     */
-    handle_tracker_generation_t nextGeneration(handle_tracker_slot_t index);
-
 };
 
-#endif //UTILITY_HANDLETRACKER_H
+#endif //UTILITY_HANDLE_TRACKER_H
diff --git a/media/liboboe/src/utility/MonotonicCounter.h b/media/liboboe/src/utility/MonotonicCounter.h
index befad21..81d7f89 100644
--- a/media/liboboe/src/utility/MonotonicCounter.h
+++ b/media/liboboe/src/utility/MonotonicCounter.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef UTILITY_MONOTONICCOUNTER_H
-#define UTILITY_MONOTONICCOUNTER_H
+#ifndef UTILITY_MONOTONIC_COUNTER_H
+#define UTILITY_MONOTONIC_COUNTER_H
 
 #include <stdint.h>
 
@@ -88,4 +88,4 @@
 };
 
 
-#endif //UTILITY_MONOTONICCOUNTER_H
+#endif //UTILITY_MONOTONIC_COUNTER_H
diff --git a/media/liboboe/src/utility/OboeUtilities.cpp b/media/liboboe/src/utility/OboeUtilities.cpp
index d9d2e88..fcf4252 100644
--- a/media/liboboe/src/utility/OboeUtilities.cpp
+++ b/media/liboboe/src/utility/OboeUtilities.cpp
@@ -30,11 +30,11 @@
 oboe_size_bytes_t OboeConvert_formatToSizeInBytes(oboe_audio_format_t format) {
     oboe_size_bytes_t size = OBOE_ERROR_ILLEGAL_ARGUMENT;
     switch (format) {
-        case OBOE_AUDIO_FORMAT_PCM16:
+        case OBOE_AUDIO_FORMAT_PCM_I16:
             size = sizeof(int16_t);
             break;
-        case OBOE_AUDIO_FORMAT_PCM32:
-        case OBOE_AUDIO_FORMAT_PCM824:
+        case OBOE_AUDIO_FORMAT_PCM_I32:
+        case OBOE_AUDIO_FORMAT_PCM_I8_24:
             size = sizeof(int32_t);
             break;
         case OBOE_AUDIO_FORMAT_PCM_FLOAT:
@@ -67,14 +67,47 @@
     }
 }
 
-oboe_result_t OboeConvert_androidToOboeError(status_t error) {
-    if (error >= 0) {
-        return error;
+status_t OboeConvert_oboeToAndroidStatus(oboe_result_t result) {
+    // This covers the case for OBOE_OK and for positive results.
+    if (result >= 0) {
+        return result;
+    }
+    status_t status;
+    switch (result) {
+    case OBOE_ERROR_DISCONNECTED:
+    case OBOE_ERROR_INVALID_HANDLE:
+        status = DEAD_OBJECT;
+        break;
+    case OBOE_ERROR_INVALID_STATE:
+        status = INVALID_OPERATION;
+        break;
+    case OBOE_ERROR_UNEXPECTED_VALUE: // TODO redundant?
+    case OBOE_ERROR_ILLEGAL_ARGUMENT:
+        status = BAD_VALUE;
+        break;
+    case OBOE_ERROR_WOULD_BLOCK:
+        status = WOULD_BLOCK;
+        break;
+    // TODO add more result codes
+    default:
+        status = UNKNOWN_ERROR;
+        break;
+    }
+    return status;
+}
+
+oboe_result_t OboeConvert_androidToOboeResult(status_t status) {
+    // This covers the case for OK and for positive result.
+    if (status >= 0) {
+        return status;
     }
     oboe_result_t result;
-    switch (error) {
-    case OK:
-        result = OBOE_OK;
+    switch (status) {
+    case BAD_TYPE:
+        result = OBOE_ERROR_INVALID_HANDLE;
+        break;
+    case DEAD_OBJECT:
+        result = OBOE_ERROR_DISCONNECTED;
         break;
     case INVALID_OPERATION:
         result = OBOE_ERROR_INVALID_STATE;
@@ -85,7 +118,7 @@
     case WOULD_BLOCK:
         result = OBOE_ERROR_WOULD_BLOCK;
         break;
-    // TODO add more error codes
+    // TODO add more status codes
     default:
         result = OBOE_ERROR_INTERNAL;
         break;
@@ -96,16 +129,16 @@
 audio_format_t OboeConvert_oboeToAndroidDataFormat(oboe_audio_format_t oboeFormat) {
     audio_format_t androidFormat;
     switch (oboeFormat) {
-    case OBOE_AUDIO_FORMAT_PCM16:
+    case OBOE_AUDIO_FORMAT_PCM_I16:
         androidFormat = AUDIO_FORMAT_PCM_16_BIT;
         break;
     case OBOE_AUDIO_FORMAT_PCM_FLOAT:
         androidFormat = AUDIO_FORMAT_PCM_FLOAT;
         break;
-    case OBOE_AUDIO_FORMAT_PCM824:
+    case OBOE_AUDIO_FORMAT_PCM_I8_24:
         androidFormat = AUDIO_FORMAT_PCM_8_24_BIT;
         break;
-    case OBOE_AUDIO_FORMAT_PCM32:
+    case OBOE_AUDIO_FORMAT_PCM_I32:
         androidFormat = AUDIO_FORMAT_PCM_32_BIT;
         break;
     default:
@@ -120,16 +153,16 @@
     oboe_audio_format_t oboeFormat = OBOE_AUDIO_FORMAT_INVALID;
     switch (androidFormat) {
     case AUDIO_FORMAT_PCM_16_BIT:
-        oboeFormat = OBOE_AUDIO_FORMAT_PCM16;
+        oboeFormat = OBOE_AUDIO_FORMAT_PCM_I16;
         break;
     case AUDIO_FORMAT_PCM_FLOAT:
         oboeFormat = OBOE_AUDIO_FORMAT_PCM_FLOAT;
         break;
     case AUDIO_FORMAT_PCM_32_BIT:
-        oboeFormat = OBOE_AUDIO_FORMAT_PCM32;
+        oboeFormat = OBOE_AUDIO_FORMAT_PCM_I32;
         break;
     case AUDIO_FORMAT_PCM_8_24_BIT:
-        oboeFormat = OBOE_AUDIO_FORMAT_PCM824;
+        oboeFormat = OBOE_AUDIO_FORMAT_PCM_I8_24;
         break;
     default:
         oboeFormat = OBOE_AUDIO_FORMAT_INVALID;
diff --git a/media/liboboe/src/utility/OboeUtilities.h b/media/liboboe/src/utility/OboeUtilities.h
index 974ccf6..4096e2a 100644
--- a/media/liboboe/src/utility/OboeUtilities.h
+++ b/media/liboboe/src/utility/OboeUtilities.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef UTILITY_OBOEUTILITIES_H
-#define UTILITY_OBOEUTILITIES_H
+#ifndef UTILITY_OBOE_UTILITIES_H
+#define UTILITY_OBOE_UTILITIES_H
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -25,7 +25,15 @@
 
 #include "oboe/OboeDefinitions.h"
 
-oboe_result_t OboeConvert_androidToOboeError(android::status_t error);
+/**
+ * Convert an Oboe result into the closest matching Android status.
+ */
+android::status_t OboeConvert_oboeToAndroidStatus(oboe_result_t result);
+
+/**
+ * Convert an Android status into the closest matching Oboe result.
+ */
+oboe_result_t OboeConvert_androidToOboeResult(android::status_t status);
 
 void OboeConvert_floatToPcm16(const float *source, int32_t numSamples, int16_t *destination);
 
@@ -51,4 +59,4 @@
  */
 oboe_size_bytes_t OboeConvert_formatToSizeInBytes(oboe_audio_format_t format);
 
-#endif //UTILITY_OBOEUTILITIES_H
+#endif //UTILITY_OBOE_UTILITIES_H
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index c2407f7..d8f5106 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -113,7 +113,9 @@
         libstagefright_foundation \
         libdl \
         libRScpp \
-	libhidlbase \
+        libhidlbase \
+        android.hardware.media.omx@1.0 \
+        android.hardware.media.omx@1.0-utils \
 
 LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libmedia
 
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index a29aff0..b4e694c 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -29,6 +29,8 @@
 
 #include "include/OMX.h"
 
+#include "omx/hal/1.0/utils/WOmx.h"
+
 namespace android {
 
 OMXClient::OMXClient() {
@@ -53,6 +55,21 @@
     return OK;
 }
 
+status_t OMXClient::connectTreble() {
+    using namespace ::android::hardware::media::omx::V1_0;
+    sp<IOmx> tOmx = IOmx::getService("default");
+    if (tOmx.get() == nullptr) {
+        ALOGE("Cannot obtain Treble IOmx.");
+        return NO_INIT;
+    }
+    if (!tOmx->isRemote()) {
+        ALOGE("Treble IOmx is in passthrough mode.");
+        return NO_INIT;
+    }
+    mOMX = new utils::LWOmx(tOmx);
+    return OK;
+}
+
 void OMXClient::disconnect() {
     mOMX.clear();
 }
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index a1c4979..6e7ef35 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -457,7 +457,10 @@
     const uint8_t *nalStart;
     size_t nalSize;
     while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
-        CHECK_GT(nalSize, 0u);
+        if (nalSize == 0u) {
+            ALOGW("skipping empty nal unit from potentially malformed bitstream");
+            continue;
+        }
 
         unsigned nalType = nalStart[0] & 0x1f;
 
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index cdce932..7a9240b 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -172,7 +172,8 @@
         return NULL;
     }
 
-    status_t err = drm->createPlugin(uuid);
+    String8 nullPackageName;
+    status_t err = drm->createPlugin(uuid, nullPackageName);
 
     if (err != OK) {
         return NULL;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index a248912..1b39e22 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1878,7 +1878,7 @@
               config->channel_mask,
               flags);
 
-    if (*devices == AUDIO_DEVICE_NONE) {
+    if (devices == NULL || *devices == AUDIO_DEVICE_NONE) {
         return BAD_VALUE;
     }
 
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index a0a3383..f44fd08 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -47,43 +47,25 @@
 
 status_t CameraProviderManager::initialize(wp<CameraProviderManager::StatusListener> listener,
         ServiceInteractionProxy* proxy) {
-    int numProviders = 0;
-    {
-        std::lock_guard<std::mutex> lock(mInterfaceMutex);
-        if (proxy == nullptr) {
-            ALOGE("%s: No valid service interaction proxy provided", __FUNCTION__);
-            return BAD_VALUE;
-        }
-        mListener = listener;
-        mServiceProxy = proxy;
-
-        // Registering will trigger notifications for all already-known providers
-        bool success = mServiceProxy->registerForNotifications(
-            /* instance name, empty means no filter */ "",
-            this);
-        if (!success) {
-            ALOGE("%s: Unable to register with hardware service manager for notifications "
-                    "about camera providers", __FUNCTION__);
-            return INVALID_OPERATION;
-        }
-        numProviders = mProviders.size();
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+    if (proxy == nullptr) {
+        ALOGE("%s: No valid service interaction proxy provided", __FUNCTION__);
+        return BAD_VALUE;
     }
+    mListener = listener;
+    mServiceProxy = proxy;
 
-    if (numProviders == 0) {
-        // Remote provider might have not been initialized
-        // Wait for a bit and see if we get one registered
-        std::mutex mtx;
-        std::unique_lock<std::mutex> lock(mtx);
-        mProviderRegistered.wait_for(lock, std::chrono::seconds(15));
-        if (mProviders.size() == 0) {
-            ALOGI("%s: Unable to get one registered provider within timeout!",
-                    __FUNCTION__);
-            std::lock_guard<std::mutex> lock(mInterfaceMutex);
-            // See if there's a passthrough HAL, but let's not complain if there's not
-            addProvider(kLegacyProviderName, /*expected*/ false);
-        }
+    // Registering will trigger notifications for all already-known providers
+    bool success = mServiceProxy->registerForNotifications(
+        /* instance name, empty means no filter */ "",
+        this);
+    if (!success) {
+        ALOGE("%s: Unable to register with hardware service manager for notifications "
+                "about camera providers", __FUNCTION__);
+        return INVALID_OPERATION;
     }
-
+    // See if there's a passthrough HAL, but let's not complain if there's not
+    addProvider(kLegacyProviderName, /*expected*/ false);
     return OK;
 }
 
@@ -294,7 +276,6 @@
     std::lock_guard<std::mutex> lock(mInterfaceMutex);
 
     addProvider(name);
-    mProviderRegistered.notify_one();
     return hardware::Return<void>();
 }
 
@@ -334,12 +315,11 @@
             mServiceProxy->getService(newProvider);
 
     if (interface == nullptr) {
+        ALOGW("%s: Camera provider HAL '%s' is not actually available", __FUNCTION__,
+                newProvider.c_str());
         if (expected) {
-            ALOGW("%s: Camera provider HAL '%s' is not actually available", __FUNCTION__,
-                    newProvider.c_str());
             return BAD_VALUE;
         } else {
-            // Not guaranteed to be found, so not an error if it wasn't
             return OK;
         }
     }
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index f21e07d..5ae16cd 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -20,7 +20,6 @@
 #include <vector>
 #include <string>
 #include <mutex>
-#include <condition_variable>
 
 #include <camera/CameraParameters2.h>
 #include <camera/CameraMetadata.h>
@@ -220,8 +219,6 @@
     // All private members, unless otherwise noted, expect mInterfaceMutex to be locked before use
     mutable std::mutex mInterfaceMutex;
 
-    std::condition_variable mProviderRegistered;
-
     // the status listener update callbacks will lock mStatusMutex
     mutable std::mutex mStatusListenerMutex;
     wp<StatusListener> mListener;
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index eacafdd..35c1f5b 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -280,6 +280,7 @@
     nsecs_t ts_since = 0;
     String16 clearOption("-clear");
     String16 sinceOption("-since");
+    String16 helpOption("-help");
     int n = args.size();
     for (int i = 0; i < n; i++) {
         String8 myarg(args[i]);
@@ -298,6 +299,16 @@
             } else {
                 ts_since = 0;
             }
+            // command line is milliseconds; internal units are nano-seconds
+            ts_since *= 1000*1000;
+        } else if (args[i] == helpOption) {
+            result.append("Recognized parameters:\n");
+            result.append("-help        this help message\n");
+            result.append("-clear       clears out saved records\n");
+            result.append("-since XXX   include records since XXX\n");
+            result.append("             (XXX is milliseconds since the UNIX epoch)\n");
+            write(fd, result.string(), result.size());
+            return NO_ERROR;
         }
     }
 
@@ -364,8 +375,6 @@
 }
 
 String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList, nsecs_t ts_since) {
-    const size_t SIZE = 512;
-    char buffer[SIZE];
     String8 result;
     int slot = 0;
 
@@ -379,12 +388,7 @@
                 continue;
             }
             AString entry = (*it)->toString();
-            snprintf(buffer, sizeof(buffer), "%4d: %s",
-                        slot, entry.c_str());
-            result.append(buffer);
-            buffer[0] = '\n';
-            buffer[1] = '\0';
-            result.append(buffer);
+            result.appendFormat("%5d: %s\n", slot, entry.c_str());
             slot++;
         }
     }
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index a5f0751..4cbf737 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -17,7 +17,8 @@
 LOCAL_REQUIRED_MODULES_arm := mediacodec-seccomp.policy
 LOCAL_SRC_FILES := main_codecservice.cpp minijail/minijail.cpp
 LOCAL_SHARED_LIBRARIES := libmedia libmediacodecservice libbinder libutils \
-	liblog libminijail
+    liblog libminijail libcutils \
+    android.hardware.media.omx@1.0
 LOCAL_C_INCLUDES := \
     $(TOP)/frameworks/av/media/libstagefright \
     $(TOP)/frameworks/native/include/media/openmax
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index a2868c1..f6cde85 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -25,11 +25,14 @@
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
 #include <utils/Log.h>
+#include <cutils/properties.h>
 
 // from LOCAL_C_INCLUDES
 #include "MediaCodecService.h"
 #include "minijail/minijail.h"
 
+#include <android/hardware/media/omx/1.0/IOmx.h>
+
 using namespace android;
 
 int main(int argc __unused, char** argv)
@@ -42,6 +45,21 @@
     sp<ProcessState> proc(ProcessState::self());
     sp<IServiceManager> sm = defaultServiceManager();
     MediaCodecService::instantiate();
+
+    // Treble
+    bool useTrebleOmx = bool(property_get_bool("debug.treble_omx", 0));
+    if (useTrebleOmx) {
+        using namespace ::android::hardware::media::omx::V1_0;
+        sp<IOmx> omx = IOmx::getService(true);
+        if (omx == nullptr) {
+            ALOGE("Cannot create a Treble IOmx service.");
+        } else if (omx->registerAsService("default") != OK) {
+            ALOGE("Cannot register a Treble IOmx service.");
+        } else {
+            ALOGV("Treble IOmx service created.");
+        }
+    }
+
     ProcessState::self()->startThreadPool();
     IPCThreadState::self()->joinThreadPool();
 }
diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk
index f667068..2bf2201 100644
--- a/services/mediadrm/Android.mk
+++ b/services/mediadrm/Android.mk
@@ -24,9 +24,8 @@
     libbinder \
     liblog \
     libmediadrm \
-    libutils \
-    libandroidfw
-ifeq ($(ENABLE_TREBLE_DRM), true)
+    libutils
+ifeq ($(ENABLE_TREBLE), true)
 LOCAL_SHARED_LIBRARIES += \
     libhidlbase \
     libhidlmemory \
@@ -35,8 +34,8 @@
 endif
 
 LOCAL_CFLAGS += -Wall -Wextra -Werror
-ifeq ($(ENABLE_TREBLE_DRM), true)
-LOCAL_CFLAGS += -DENABLE_TREBLE_DRM=1
+ifeq ($(ENABLE_TREBLE), true)
+LOCAL_CFLAGS += -DENABLE_TREBLE=1
 endif
 
 LOCAL_MODULE:= mediadrmserver
diff --git a/services/mediadrm/MediaDrmService.cpp b/services/mediadrm/MediaDrmService.cpp
index c709b5e..e579dd8 100644
--- a/services/mediadrm/MediaDrmService.cpp
+++ b/services/mediadrm/MediaDrmService.cpp
@@ -24,7 +24,7 @@
 #include <binder/IServiceManager.h>
 #include <utils/Log.h>
 
-#ifdef ENABLE_TREBLE_DRM
+#ifdef ENABLE_TREBLE
 #include <media/CryptoHal.h>
 #include <media/DrmHal.h>
 #else
@@ -40,7 +40,7 @@
 }
 
 sp<ICrypto> MediaDrmService::makeCrypto() {
-#ifdef ENABLE_TREBLE_DRM
+#ifdef ENABLE_TREBLE
     return new CryptoHal;
 #else
     return new Crypto;
@@ -48,7 +48,7 @@
 }
 
 sp<IDrm> MediaDrmService::makeDrm() {
-#ifdef ENABLE_TREBLE_DRM
+#ifdef ENABLE_TREBLE
     return new DrmHal;
 #else
     return new Drm;
diff --git a/services/oboeservice/Android.mk b/services/oboeservice/Android.mk
index 07b4d76..5a79b80 100644
--- a/services/oboeservice/Android.mk
+++ b/services/oboeservice/Android.mk
@@ -42,7 +42,9 @@
     OboeAudioService.cpp \
     OboeServiceStreamBase.cpp \
     OboeServiceStreamFakeHal.cpp \
-    OboeServiceMain.cpp
+    TimestampScheduler.cpp \
+    OboeServiceMain.cpp \
+    OboeThread.cpp
 
 LOCAL_CFLAGS += -Wno-unused-parameter
 LOCAL_CFLAGS += -Wall -Werror
diff --git a/services/oboeservice/OboeAudioService.cpp b/services/oboeservice/OboeAudioService.cpp
index caddc1d..001569c 100644
--- a/services/oboeservice/OboeAudioService.cpp
+++ b/services/oboeservice/OboeAudioService.cpp
@@ -34,11 +34,20 @@
 
 typedef enum
 {
+    OBOE_HANDLE_TYPE_DUMMY1, // TODO remove DUMMYs
+    OBOE_HANDLE_TYPE_DUMMY2, // make server handles different than client
     OBOE_HANDLE_TYPE_STREAM,
     OBOE_HANDLE_TYPE_COUNT
 } oboe_service_handle_type_t;
 static_assert(OBOE_HANDLE_TYPE_COUNT <= HANDLE_TRACKER_MAX_TYPES, "Too many handle types.");
 
+android::OboeAudioService::OboeAudioService()
+    : BnOboeAudioService() {
+}
+
+OboeAudioService::~OboeAudioService() {
+}
+
 oboe_handle_t OboeAudioService::openStream(oboe::OboeStreamRequest &request,
                                                 oboe::OboeStreamConfiguration &configuration) {
     OboeServiceStreamBase *serviceStream =  new OboeServiceStreamFakeHal();
@@ -61,7 +70,7 @@
     OboeServiceStreamBase *serviceStream = (OboeServiceStreamBase *)
             mHandleTracker.remove(OBOE_HANDLE_TYPE_STREAM,
                                   streamHandle);
-    ALOGI("OboeAudioService.closeStream(0x%08X)", streamHandle);
+    ALOGD("OboeAudioService.closeStream(0x%08X)", streamHandle);
     if (serviceStream != nullptr) {
         ALOGD("OboeAudioService::closeStream(): deleting serviceStream = %p", serviceStream);
         delete serviceStream;
@@ -79,9 +88,8 @@
 oboe_result_t OboeAudioService::getStreamDescription(
                 oboe_handle_t streamHandle,
                 oboe::AudioEndpointParcelable &parcelable) {
-    ALOGI("OboeAudioService::getStreamDescriptor(), streamHandle = 0x%08x", streamHandle);
     OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    ALOGI("OboeAudioService::getStreamDescriptor(), serviceStream = %p", serviceStream);
+    ALOGD("OboeAudioService::getStreamDescription(), serviceStream = %p", serviceStream);
     if (serviceStream == nullptr) {
         return OBOE_ERROR_INVALID_HANDLE;
     }
@@ -90,45 +98,38 @@
 
 oboe_result_t OboeAudioService::startStream(oboe_handle_t streamHandle) {
     OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    ALOGI("OboeAudioService::startStream(), serviceStream = %p", serviceStream);
+    ALOGD("OboeAudioService::startStream(), serviceStream = %p", serviceStream);
     if (serviceStream == nullptr) {
         return OBOE_ERROR_INVALID_HANDLE;
     }
-    mLatestHandle = streamHandle;
-    return serviceStream->start();
+    oboe_result_t result = serviceStream->start();
+    return result;
 }
 
 oboe_result_t OboeAudioService::pauseStream(oboe_handle_t streamHandle) {
     OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    ALOGI("OboeAudioService::pauseStream(), serviceStream = %p", serviceStream);
+    ALOGD("OboeAudioService::pauseStream(), serviceStream = %p", serviceStream);
     if (serviceStream == nullptr) {
         return OBOE_ERROR_INVALID_HANDLE;
     }
-    return serviceStream->pause();
+    oboe_result_t result = serviceStream->pause();
+    return result;
 }
 
 oboe_result_t OboeAudioService::flushStream(oboe_handle_t streamHandle) {
     OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    ALOGI("OboeAudioService::flushStream(), serviceStream = %p", serviceStream);
+    ALOGD("OboeAudioService::flushStream(), serviceStream = %p", serviceStream);
     if (serviceStream == nullptr) {
         return OBOE_ERROR_INVALID_HANDLE;
     }
     return serviceStream->flush();
 }
 
-void OboeAudioService::tickle() {
-    OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(mLatestHandle);
-    //ALOGI("OboeAudioService::tickle(), serviceStream = %p", serviceStream);
-    if (serviceStream != nullptr) {
-        serviceStream->tickle();
-    }
-}
-
 oboe_result_t OboeAudioService::registerAudioThread(oboe_handle_t streamHandle,
                                                          pid_t clientThreadId,
                                                          oboe_nanoseconds_t periodNanoseconds) {
     OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    ALOGI("OboeAudioService::registerAudioThread(), serviceStream = %p", serviceStream);
+    ALOGD("OboeAudioService::registerAudioThread(), serviceStream = %p", serviceStream);
     if (serviceStream == nullptr) {
         ALOGE("OboeAudioService::registerAudioThread(), serviceStream == nullptr");
         return OBOE_ERROR_INVALID_HANDLE;
diff --git a/services/oboeservice/OboeAudioService.h b/services/oboeservice/OboeAudioService.h
index df3cbf8..b196f1d 100644
--- a/services/oboeservice/OboeAudioService.h
+++ b/services/oboeservice/OboeAudioService.h
@@ -24,31 +24,32 @@
 
 #include <oboe/OboeDefinitions.h>
 #include <oboe/OboeAudio.h>
-#include "HandleTracker.h"
+#include "utility/HandleTracker.h"
 #include "IOboeAudioService.h"
-#include "OboeService.h"
 #include "OboeServiceStreamBase.h"
 
-using namespace android;
-namespace oboe {
+namespace android {
 
 class OboeAudioService :
     public BinderService<OboeAudioService>,
     public BnOboeAudioService
 {
-    friend class BinderService<OboeAudioService>;   // for OboeAudioService()
+    friend class BinderService<OboeAudioService>;
+
 public:
-// TODO why does this fail?    static const char* getServiceName() ANDROID_API { return "media.audio_oboe"; }
+    OboeAudioService();
+    virtual ~OboeAudioService();
+
     static const char* getServiceName() { return "media.audio_oboe"; }
 
-    virtual oboe_handle_t openStream(OboeStreamRequest &request,
-                                     OboeStreamConfiguration &configuration);
+    virtual oboe_handle_t openStream(oboe::OboeStreamRequest &request,
+                                     oboe::OboeStreamConfiguration &configuration);
 
     virtual oboe_result_t closeStream(oboe_handle_t streamHandle);
 
     virtual oboe_result_t getStreamDescription(
                 oboe_handle_t streamHandle,
-                AudioEndpointParcelable &parcelable);
+                oboe::AudioEndpointParcelable &parcelable);
 
     virtual oboe_result_t startStream(oboe_handle_t streamHandle);
 
@@ -61,16 +62,14 @@
 
     virtual oboe_result_t unregisterAudioThread(oboe_handle_t streamHandle, pid_t pid);
 
-    virtual void tickle();
-
 private:
 
-    OboeServiceStreamBase *convertHandleToServiceStream(oboe_handle_t streamHandle) const;
+    oboe::OboeServiceStreamBase *convertHandleToServiceStream(oboe_handle_t streamHandle) const;
 
     HandleTracker mHandleTracker;
-    oboe_handle_t mLatestHandle = OBOE_ERROR_INVALID_HANDLE; // TODO until we have service threads
+
 };
 
-} /* namespace oboe */
+} /* namespace android */
 
 #endif //OBOE_OBOE_AUDIO_SERVICE_H
diff --git a/services/oboeservice/OboeServiceStreamBase.cpp b/services/oboeservice/OboeServiceStreamBase.cpp
index 6b7e4e5..15b70a5 100644
--- a/services/oboeservice/OboeServiceStreamBase.cpp
+++ b/services/oboeservice/OboeServiceStreamBase.cpp
@@ -40,12 +40,15 @@
 }
 
 OboeServiceStreamBase::~OboeServiceStreamBase() {
+    Mutex::Autolock _l(mLockUpMessageQueue);
     delete mUpMessageQueue;
 }
 
 void OboeServiceStreamBase::sendServiceEvent(oboe_service_event_t event,
                               int32_t data1,
                               int64_t data2) {
+
+    Mutex::Autolock _l(mLockUpMessageQueue);
     OboeServiceMessage command;
     command.what = OboeServiceMessage::code::EVENT;
     command.event.event = event;
diff --git a/services/oboeservice/OboeServiceStreamBase.h b/services/oboeservice/OboeServiceStreamBase.h
index 736c754..33857c6 100644
--- a/services/oboeservice/OboeServiceStreamBase.h
+++ b/services/oboeservice/OboeServiceStreamBase.h
@@ -17,12 +17,14 @@
 #ifndef OBOE_OBOE_SERVICE_STREAM_BASE_H
 #define OBOE_OBOE_SERVICE_STREAM_BASE_H
 
+#include <utils/Mutex.h>
+
 #include "IOboeAudioService.h"
 #include "OboeService.h"
-#include "AudioStream.h"
 #include "fifo/FifoBuffer.h"
 #include "SharedRingBuffer.h"
 #include "AudioEndpointParcelable.h"
+#include "OboeThread.h"
 
 namespace oboe {
 
@@ -30,7 +32,7 @@
 // This should be way more than we need.
 #define QUEUE_UP_CAPACITY_COMMANDS (128)
 
-class OboeServiceStreamBase  {
+class OboeServiceStreamBase {
 
 public:
     OboeServiceStreamBase();
@@ -68,7 +70,11 @@
 
     virtual oboe_result_t close() = 0;
 
-    virtual void tickle() = 0;
+    virtual void sendCurrentTimestamp() = 0;
+
+    oboe_size_frames_t getFramesPerBurst() {
+        return mFramesPerBurst;
+    }
 
     virtual void sendServiceEvent(oboe_service_event_t event,
                                   int32_t data1 = 0,
@@ -77,6 +83,7 @@
     virtual void setRegisteredThread(pid_t pid) {
         mRegisteredClientThread = pid;
     }
+
     virtual pid_t getRegisteredThread() {
         return mRegisteredClientThread;
     }
@@ -92,6 +99,8 @@
     oboe_size_frames_t       mFramesPerBurst = 0;
     oboe_size_frames_t       mCapacityInFrames = 0;
     oboe_size_bytes_t        mCapacityInBytes = 0;
+
+    android::Mutex           mLockUpMessageQueue;
 };
 
 } /* namespace oboe */
diff --git a/services/oboeservice/OboeServiceStreamFakeHal.cpp b/services/oboeservice/OboeServiceStreamFakeHal.cpp
index dbbc860..da4099d 100644
--- a/services/oboeservice/OboeServiceStreamFakeHal.cpp
+++ b/services/oboeservice/OboeServiceStreamFakeHal.cpp
@@ -18,6 +18,8 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <atomic>
+
 #include "AudioClock.h"
 #include "AudioEndpointParcelable.h"
 
@@ -41,6 +43,7 @@
         : OboeServiceStreamBase()
         , mStreamId(nullptr)
         , mPreviousFrameCounter(0)
+        , mOboeThread()
 {
 }
 
@@ -86,7 +89,8 @@
     // Fill in OboeStreamConfiguration
     configuration.setSampleRate(mSampleRate);
     configuration.setSamplesPerFrame(mmapInfo.channel_count);
-    configuration.setAudioFormat(OBOE_AUDIO_FORMAT_PCM16);
+    configuration.setAudioFormat(OBOE_AUDIO_FORMAT_PCM_I16);
+
     return OBOE_OK;
 }
 
@@ -117,6 +121,10 @@
     oboe_result_t result = fake_hal_start(mStreamId);
     sendServiceEvent(OBOE_SERVICE_EVENT_STARTED);
     mState = OBOE_STREAM_STATE_STARTED;
+    if (result == OBOE_OK) {
+        mThreadEnabled.store(true);
+        result = mOboeThread.start(this);
+    }
     return result;
 }
 
@@ -131,6 +139,8 @@
     mState = OBOE_STREAM_STATE_PAUSED;
     mFramesRead.reset32();
     ALOGD("OboeServiceStreamFakeHal::pause() sent OBOE_SERVICE_EVENT_PAUSED");
+    mThreadEnabled.store(false);
+    result = mOboeThread.stop();
     return result;
 }
 
@@ -166,7 +176,7 @@
         command.what = OboeServiceMessage::code::TIMESTAMP;
         mFramesRead.update32(frameCounter);
         command.timestamp.position = mFramesRead.get();
-        ALOGV("OboeServiceStreamFakeHal::sendCurrentTimestamp() HAL frames = %d, pos = %d",
+        ALOGD("OboeServiceStreamFakeHal::sendCurrentTimestamp() HAL frames = %d, pos = %d",
                 frameCounter, (int)mFramesRead.get());
         command.timestamp.timestamp = AudioClock::getNanoseconds();
         mUpMessageQueue->getFifoBuffer()->write(&command, 1);
@@ -174,17 +184,18 @@
     }
 }
 
-void OboeServiceStreamFakeHal::tickle() {
-    if (mStreamId != nullptr) {
-        switch (mState) {
-            case OBOE_STREAM_STATE_STARTING:
-            case OBOE_STREAM_STATE_STARTED:
-            case OBOE_STREAM_STATE_PAUSING:
-            case OBOE_STREAM_STATE_STOPPING:
-                sendCurrentTimestamp();
-                break;
-            default:
-                break;
+// implement Runnable
+void OboeServiceStreamFakeHal::run() {
+    TimestampScheduler timestampScheduler;
+    timestampScheduler.setBurstPeriod(mFramesPerBurst, mSampleRate);
+    timestampScheduler.start(AudioClock::getNanoseconds());
+    while(mThreadEnabled.load()) {
+        oboe_nanoseconds_t nextTime = timestampScheduler.nextAbsoluteTime();
+        if (AudioClock::getNanoseconds() >= nextTime) {
+            sendCurrentTimestamp();
+        } else  {
+            // Sleep until it is time to send the next timestamp.
+            AudioClock::sleepUntilNanoTime(nextTime);
         }
     }
 }
diff --git a/services/oboeservice/OboeServiceStreamFakeHal.h b/services/oboeservice/OboeServiceStreamFakeHal.h
index b026d34..39b952a 100644
--- a/services/oboeservice/OboeServiceStreamFakeHal.h
+++ b/services/oboeservice/OboeServiceStreamFakeHal.h
@@ -22,10 +22,13 @@
 #include "FakeAudioHal.h"
 #include "MonotonicCounter.h"
 #include "AudioEndpointParcelable.h"
+#include "TimestampScheduler.h"
 
 namespace oboe {
 
-class OboeServiceStreamFakeHal : public OboeServiceStreamBase {
+class OboeServiceStreamFakeHal
+    : public OboeServiceStreamBase
+    , public Runnable {
 
 public:
     OboeServiceStreamFakeHal();
@@ -53,12 +56,10 @@
 
     virtual oboe_result_t close() override;
 
-    virtual void tickle() override;
-
-protected:
-
     void sendCurrentTimestamp();
 
+    virtual void run() override; // to implement Runnable
+
 private:
     fake_hal_stream_ptr    mStreamId; // Move to HAL
 
@@ -68,6 +69,9 @@
     int                    mPreviousFrameCounter = 0;   // from HAL
 
     oboe_stream_state_t    mState = OBOE_STREAM_STATE_UNINITIALIZED;
+
+    OboeThread             mOboeThread;
+    std::atomic<bool>      mThreadEnabled;
 };
 
 } // namespace oboe
diff --git a/services/oboeservice/OboeThread.cpp b/services/oboeservice/OboeThread.cpp
new file mode 100644
index 0000000..9ecfa90
--- /dev/null
+++ b/services/oboeservice/OboeThread.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OboeService"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <pthread.h>
+
+#include <oboe/OboeDefinitions.h>
+
+#include "OboeThread.h"
+
+using namespace oboe;
+
+
+OboeThread::OboeThread() {
+    // mThread is a pthread_t of unknown size so we need memset.
+    memset(&mThread, 0, sizeof(mThread));
+}
+
+void OboeThread::dispatch() {
+    if (mRunnable != nullptr) {
+        mRunnable->run();
+    } else {
+        run();
+    }
+}
+
+// This is the entry point for the new thread created by createThread().
+// It converts the 'C' function call to a C++ method call.
+static void * OboeThread_internalThreadProc(void *arg) {
+    OboeThread *oboeThread = (OboeThread *) arg;
+    oboeThread->dispatch();
+    return nullptr;
+}
+
+oboe_result_t OboeThread::start(Runnable *runnable) {
+    if (mHasThread) {
+        return OBOE_ERROR_INVALID_STATE;
+    }
+    mRunnable = runnable; // TODO use atomic?
+    int err = pthread_create(&mThread, nullptr, OboeThread_internalThreadProc, this);
+    if (err != 0) {
+        ALOGE("OboeThread::pthread_create() returned %d", err);
+        // TODO convert errno to oboe_result_t
+        return OBOE_ERROR_INTERNAL;
+    } else {
+        mHasThread = true;
+        return OBOE_OK;
+    }
+}
+
+oboe_result_t OboeThread::stop() {
+    if (!mHasThread) {
+        return OBOE_ERROR_INVALID_STATE;
+    }
+    int err = pthread_join(mThread, nullptr);
+    mHasThread = false;
+    // TODO convert errno to oboe_result_t
+    return err ? OBOE_ERROR_INTERNAL : OBOE_OK;
+}
+
diff --git a/services/oboeservice/OboeThread.h b/services/oboeservice/OboeThread.h
new file mode 100644
index 0000000..48fafc7
--- /dev/null
+++ b/services/oboeservice/OboeThread.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OBOE_THREAD_H
+#define OBOE_THREAD_H
+
+#include <atomic>
+#include <pthread.h>
+
+#include <oboe/OboeDefinitions.h>
+
+namespace oboe {
+
+class Runnable {
+public:
+    Runnable() {};
+    virtual ~Runnable() = default;
+
+    virtual void run() {}
+};
+
+/**
+ * Abstraction for a host thread.
+ */
+class OboeThread
+{
+public:
+    OboeThread();
+    OboeThread(Runnable *runnable);
+    virtual ~OboeThread() = default;
+
+    /**
+     * Start the thread running.
+     */
+    oboe_result_t start(Runnable *runnable = nullptr);
+
+    /**
+     * Join the thread.
+     * The caller must somehow tell the thread to exit before calling join().
+     */
+    oboe_result_t stop();
+
+    /**
+     * This will get called in the thread.
+     * Override this or pass a Runnable to start().
+     */
+    virtual void run() {};
+
+    void dispatch(); // called internally from 'C' thread wrapper
+
+private:
+    Runnable*                mRunnable = nullptr; // TODO make atomic with memory barrier?
+    bool                     mHasThread = false;
+    pthread_t                mThread; // initialized in constructor
+
+};
+
+} /* namespace oboe */
+
+#endif ///OBOE_THREAD_H
diff --git a/services/oboeservice/TimestampScheduler.cpp b/services/oboeservice/TimestampScheduler.cpp
new file mode 100644
index 0000000..17d6c63
--- /dev/null
+++ b/services/oboeservice/TimestampScheduler.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// for random()
+#include <stdlib.h>
+
+#include "TimestampScheduler.h"
+
+using namespace oboe;
+
+void TimestampScheduler::start(oboe_nanoseconds_t startTime) {
+    mStartTime = startTime;
+    mLastTime = startTime;
+}
+
+oboe_nanoseconds_t TimestampScheduler::nextAbsoluteTime() {
+    int64_t periodsElapsed = (mLastTime - mStartTime) / mBurstPeriod;
+    // This is an arbitrary schedule that could probably be improved.
+    // It starts out sending a timestamp on every period because we want to
+    // get an accurate picture when the stream starts. Then it slows down
+    // to the occasional timestamps needed to detect a slow drift.
+    int64_t minPeriodsToDelay = (periodsElapsed < 10) ? 1 :
+        (periodsElapsed < 100) ? 3 :
+        (periodsElapsed < 1000) ? 10 : 50;
+    oboe_nanoseconds_t sleepTime = minPeriodsToDelay * mBurstPeriod;
+    // Generate a random rectangular distribution one burst wide so that we get
+    // an uncorrelated sampling of the MMAP pointer.
+    sleepTime += (oboe_nanoseconds_t)(random() * mBurstPeriod / RAND_MAX);
+    mLastTime += sleepTime;
+    return mLastTime;
+}
diff --git a/services/oboeservice/TimestampScheduler.h b/services/oboeservice/TimestampScheduler.h
new file mode 100644
index 0000000..041e432
--- /dev/null
+++ b/services/oboeservice/TimestampScheduler.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OBOE_TIMESTAMP_SCHEDULER_H
+#define OBOE_TIMESTAMP_SCHEDULER_H
+
+//#include <stdlib.h> // random()
+
+#include "IOboeAudioService.h"
+#include "OboeService.h"
+#include "AudioStream.h"
+#include "fifo/FifoBuffer.h"
+#include "SharedRingBuffer.h"
+#include "AudioEndpointParcelable.h"
+
+namespace oboe {
+
+/**
+ * Schedule wakeup time for monitoring the position
+ * of an MMAP/NOIRQ buffer.
+ *
+ * Note that this object is not thread safe. Only call it from a single thread.
+ */
+class TimestampScheduler
+{
+public:
+    TimestampScheduler() {};
+    virtual ~TimestampScheduler() = default;
+
+    /**
+     * Start the schedule at the given time.
+     */
+    void start(oboe_nanoseconds_t startTime);
+
+    /**
+     * Calculate the next time that the read position should be
+     * measured.
+     */
+    oboe_nanoseconds_t nextAbsoluteTime();
+
+    void setBurstPeriod(oboe_nanoseconds_t burstPeriod) {
+        mBurstPeriod = burstPeriod;
+    }
+
+    void setBurstPeriod(oboe_size_frames_t framesPerBurst,
+                        oboe_sample_rate_t sampleRate) {
+        mBurstPeriod = OBOE_NANOS_PER_SECOND * framesPerBurst / sampleRate;
+    }
+
+    oboe_nanoseconds_t getBurstPeriod() {
+        return mBurstPeriod;
+    }
+
+private:
+    // Start with an arbitrary default so we do not divide by zero.
+    oboe_nanoseconds_t mBurstPeriod = OBOE_NANOS_PER_MILLISECOND;
+    oboe_nanoseconds_t mStartTime;
+    oboe_nanoseconds_t mLastTime;
+};
+
+} /* namespace oboe */
+
+#endif /* OBOE_TIMESTAMP_SCHEDULER_H */