Merge "- Support comfort noise in AMRExtractor - Support duration and seeking in AMRExtractor for different bit rates"
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 56ed3a4..361e7dc 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -44,6 +44,8 @@
         eSecure             = 0x00000080,
         eNonPremultiplied   = 0x00000100,
         eOpaque             = 0x00000400,
+        eProtectedByApp     = 0x00000800,
+        eProtectedByDRM     = 0x00001000,
 
         eFXSurfaceNormal    = 0x00000000,
         eFXSurfaceBlur      = 0x00010000,
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index 8b256f4..02d6f8f 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -54,9 +54,11 @@
         USAGE_SW_WRITE_RARELY   = GRALLOC_USAGE_SW_WRITE_RARELY,
         USAGE_SW_WRITE_OFTEN    = GRALLOC_USAGE_SW_WRITE_OFTEN,
         USAGE_SW_WRITE_MASK     = GRALLOC_USAGE_SW_WRITE_MASK,
-        
+
         USAGE_SOFTWARE_MASK     = USAGE_SW_READ_MASK|USAGE_SW_WRITE_MASK,
-        
+
+        USAGE_PROTECTED         = GRALLOC_USAGE_PROTECTED,
+
         USAGE_HW_TEXTURE        = GRALLOC_USAGE_HW_TEXTURE,
         USAGE_HW_RENDER         = GRALLOC_USAGE_HW_RENDER,
         USAGE_HW_2D             = GRALLOC_USAGE_HW_2D,
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index 654d0f3..fdc8105 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -315,6 +315,8 @@
  * If all parameters are 0, the normal behavior is restored. That is,
  * dequeued buffers following this call will be sized to the window's size.
  *
+ * Calling this function will reset the window crop to a NULL value, which
+ * disables cropping of the buffers.
  */
 static inline int native_window_set_buffers_geometry(
         ANativeWindow* window,
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index ed7f53d..6227f3e 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -1985,6 +1985,7 @@
 
 #ifndef HAVE_ANDROID_OS
     void print(bool inclValues) const;
+    static String8 normalizeForOutput(const char* input);
 #endif
 
 private:
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 1dadd53..236ff4f 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -219,11 +219,19 @@
             mSlots[mLastQueued].mEglImage = image;
             mSlots[mLastQueued].mEglDisplay = dpy;
         }
+
+        GLint error;
+        while ((error = glGetError()) != GL_NO_ERROR) {
+            LOGE("GL error cleared before updating SurfaceTexture: %#04x", error);
+        }
         glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
-        GLint error = glGetError();
-        if (error != GL_NO_ERROR) {
+        bool failed = false;
+        while ((error = glGetError()) != GL_NO_ERROR) {
             LOGE("error binding external texture image %p (slot %d): %#04x",
                     image, mLastQueued, error);
+            failed = true;
+        }
+        if (failed) {
             return -EINVAL;
         }
 
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 0ed8be5..50cbdb8 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -88,7 +88,7 @@
     int buf = -1;
     status_t err = mSurfaceTexture->dequeueBuffer(&buf);
     if (err < 0) {
-        LOGE("dequeueBuffer: ISurfaceTexture::dequeueBuffer failed: %d", err);
+        LOGV("dequeueBuffer: ISurfaceTexture::dequeueBuffer failed: %d", err);
         return err;
     }
     sp<GraphicBuffer>& gbuf(mSlots[buf]);
@@ -238,13 +238,15 @@
     LOGV("SurfaceTextureClient::setCrop");
     Mutex::Autolock lock(mMutex);
 
-    // empty/invalid rects are not allowed
-    if (rect->isEmpty())
-        return BAD_VALUE;
+    Rect realRect;
+    if (rect == NULL || rect->isEmpty()) {
+        realRect = Rect(0, 0);
+    } else {
+        realRect = *rect;
+    }
 
     status_t err = mSurfaceTexture->setCrop(*rect);
-    LOGE_IF(err, "ISurfaceTexture::setCrop(...) returned %s",
-            strerror(-err));
+    LOGE_IF(err, "ISurfaceTexture::setCrop(...) returned %s", strerror(-err));
 
     return err;
 }
@@ -280,7 +282,10 @@
     mReqHeight = h;
     mReqFormat = format;
 
-    return NO_ERROR;
+    status_t err = mSurfaceTexture->setCrop(Rect(0, 0));
+    LOGE_IF(err, "ISurfaceTexture::setCrop(...) returned %s", strerror(-err));
+
+    return err;
 }
 
 int SurfaceTextureClient::setBuffersTransform(int transform)
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index e21bab7..1e9bd74 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -827,13 +827,15 @@
 
 int Surface::crop(Rect const* rect)
 {
-    // empty/invalid rects are not allowed
-    if (rect->isEmpty())
-        return BAD_VALUE;
-
     Mutex::Autolock _l(mSurfaceLock);
     // TODO: validate rect size
-    mNextBufferCrop = *rect;
+
+    if (rect == NULL || rect->isEmpty()) {
+        mNextBufferCrop = Rect(0,0);
+    } else {
+        mNextBufferCrop = *rect;
+    }
+
     return NO_ERROR;
 }
 
@@ -884,6 +886,9 @@
         // EGLConfig validation.
         mFormat = format;
     }
+
+    mNextBufferCrop = Rect(0,0);
+
     return NO_ERROR;
 }
 
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index bbf5093..7197ad7 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -3703,9 +3703,9 @@
 void ResTable::getLocales(Vector<String8>* locales) const
 {
     Vector<ResTable_config> configs;
-    LOGD("calling getConfigurations");
+    LOGV("calling getConfigurations");
     getConfigurations(&configs);
-    LOGD("called getConfigurations size=%d", (int)configs.size());
+    LOGV("called getConfigurations size=%d", (int)configs.size());
     const size_t I = configs.size();
     for (size_t i=0; i<I; i++) {
         char locale[6];
@@ -4141,6 +4141,38 @@
     }
 }
 
+// Normalize a string for output
+String8 ResTable::normalizeForOutput( const char *input )
+{
+    String8 ret;
+    char buff[2];
+    buff[1] = '\0';
+
+    while (*input != '\0') {
+        switch (*input) {
+            // All interesting characters are in the ASCII zone, so we are making our own lives
+            // easier by scanning the string one byte at a time.
+        case '\\':
+            ret += "\\\\";
+            break;
+        case '\n':
+            ret += "\\n";
+            break;
+        case '"':
+            ret += "\\\"";
+            break;
+        default:
+            buff[0] = *input;
+            ret += buff;
+            break;
+        }
+
+        input++;
+    }
+
+    return ret;
+}
+
 void ResTable::print_value(const Package* pkg, const Res_value& value) const
 {
     if (value.dataType == Res_value::TYPE_NULL) {
@@ -4154,13 +4186,13 @@
         const char* str8 = pkg->header->values.string8At(
                 value.data, &len);
         if (str8 != NULL) {
-            printf("(string8) \"%s\"\n", str8);
+            printf("(string8) \"%s\"\n", normalizeForOutput(str8).string());
         } else {
             const char16_t* str16 = pkg->header->values.stringAt(
                     value.data, &len);
             if (str16 != NULL) {
                 printf("(string16) \"%s\"\n",
-                    String8(str16, len).string());
+                    normalizeForOutput(String8(str16, len).string()).string());
             } else {
                 printf("(string) null\n");
             }
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index ad9a94f..b1bd828 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -778,6 +778,7 @@
             // called by a new thread using the same thread ID as this one.
             self->mThread = thread_id_t(-1);
             self->mThreadExitedCondition.broadcast();
+            self->mThread = thread_id_t(-1); // thread id could be reused
             self->mLock.unlock();
             break;
         }
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 7ac6f92..a1cb23a 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -82,6 +82,11 @@
     if (ggl_unlikely(gEGLErrorKey == -1))
         return EGL_SUCCESS;
     GLint error = (GLint)pthread_getspecific(gEGLErrorKey);
+    if (error == 0) {
+        // The TLS key has been created by another thread, but the value for
+        // this thread has not been initialized.
+        return EGL_SUCCESS;
+    }
     pthread_setspecific(gEGLErrorKey, (void*)EGL_SUCCESS);
     return error;
 }
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 8977fbf..3dc8c03 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -389,10 +389,9 @@
 }
 
 static inline void clearError() {
-    if (gEGLThreadLocalStorageKey != -1) {
-        tls_t* tls = getTLS();
-        tls->error = EGL_SUCCESS;
-    }
+    // This must clear the error from all the underlying EGL implementations as
+    // well as the EGL wrapper layer.
+    eglGetError();
 }
 
 template<typename T>
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3730739..fde8e67 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -56,6 +56,8 @@
         mNeedsBlending(true),
         mNeedsDithering(false),
         mSecure(false),
+        mProtectedByApp(false),
+        mProtectedByDRM(false),
         mTextureManager(),
         mBufferManager(mTextureManager),
         mWidth(0), mHeight(0), mNeedsScaling(false), mFixedSize(false)
@@ -150,8 +152,7 @@
     // the layer is not on screen anymore. free as much resources as possible
     mFreezeLock.clear();
 
-    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
-    mBufferManager.destroy(dpy);
+    // Free our own reference to ISurface
     mSurface.clear();
 
     Mutex::Autolock _l(mLock);
@@ -191,6 +192,8 @@
     mReqHeight = h;
 
     mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
+    mProtectedByApp = (flags & ISurfaceComposer::eProtectedByApp) ? true : false;
+    mProtectedByDRM = (flags & ISurfaceComposer::eProtectedByDRM) ? true : false;
     mNeedsBlending = (info.h_alpha - info.l_alpha) > 0 &&
             (flags & ISurfaceComposer::eOpaque) == 0;
 
@@ -476,6 +479,10 @@
         // request EGLImage for all buffers
         usage |= GraphicBuffer::USAGE_HW_TEXTURE;
     }
+    if (mProtectedByApp || mProtectedByDRM) {
+        // need a hardware-protected path to external video sink
+        usage |= GraphicBuffer::USAGE_PROTECTED;
+    }
     return usage;
 }
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2908119..d9a8be3 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -79,6 +79,8 @@
     virtual bool needsDithering() const     { return mNeedsDithering; }
     virtual bool needsFiltering() const;
     virtual bool isSecure() const           { return mSecure; }
+    virtual bool isProtectedByApp() const   { return mProtectedByApp; }
+    virtual bool isProtectedByDRM() const   { return mProtectedByDRM; }
     virtual sp<Surface> createSurface() const;
     virtual status_t ditch();
     virtual void onRemoved();
@@ -218,7 +220,9 @@
     bool mNeedsDithering;
 
     // page-flip thread (currently main thread)
-    bool mSecure;
+    bool mSecure;         // no screenshots
+    bool mProtectedByApp; // application requires protected path to external sink
+    bool mProtectedByDRM; // DRM agent requires protected path to external sink
     Region mPostedDirtyRegion;
 
     // page-flip thread and transaction thread (currently main thread)
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 8d83f0b..86057f8 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -498,11 +498,9 @@
 }
 
 void LayerBase::setBufferCrop(const Rect& crop) {
-    if (!crop.isEmpty()) {
-        if (mBufferCrop != crop) {
-            mBufferCrop = crop;
-            mFlinger->invalidateHwcGeometry();
-        }
+    if (mBufferCrop != crop) {
+        mBufferCrop = crop;
+        mFlinger->invalidateHwcGeometry();
     }
 }
 
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 8ed4749..184edd7 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -196,6 +196,18 @@
      */
     virtual bool isSecure() const       { return false; }
 
+    /**
+     * isProtectedByApp - true if application says this surface is protected, that
+     * is if it requires a hardware-protected data path to an external sink.
+     */
+    virtual bool isProtectedByApp() const   { return false; }
+
+    /**
+     * isProtectedByDRM - true if DRM agent says this surface is protected, that
+     * is if it requires a hardware-protected data path to an external sink.
+     */
+    virtual bool isProtectedByDRM() const   { return false; }
+
     /** Called from the main thread, when the surface is removed from the
      * draw list */
     virtual status_t ditch() { return NO_ERROR; }
diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h
index f032314..a04a0c0 100644
--- a/services/surfaceflinger/LayerDim.h
+++ b/services/surfaceflinger/LayerDim.h
@@ -42,8 +42,10 @@
         virtual ~LayerDim();
 
     virtual void onDraw(const Region& clip) const;
-    virtual bool needsBlending() const  { return true; }
-    virtual bool isSecure() const       { return false; }
+    virtual bool needsBlending() const    { return true; }
+    virtual bool isSecure() const         { return false; }
+    virtual bool isProtectedByApp() const { return false; }
+    virtual bool isProtectedByDRM() const { return false; }
     virtual const char* getTypeId() const { return "LayerDim"; }
 
     static void initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h);