Merge "camera: Fix race condition between setParameters() and stopPreview()." into klp-dev
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index d027ba9..94c626a 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -37,11 +37,13 @@
 #include <media/ICrypto.h>
 
 #include <stdlib.h>
+#include <unistd.h>
 #include <string.h>
 #include <stdio.h>
 #include <fcntl.h>
 #include <signal.h>
 #include <getopt.h>
+#include <sys/wait.h>
 
 using namespace android;
 
@@ -498,23 +500,61 @@
 
 /*
  * Sends a broadcast to the media scanner to tell it about the new video.
+ *
+ * This is optional, but nice to have.
  */
 static status_t notifyMediaScanner(const char* fileName) {
-    String8 command("am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file://");
-    command.append(fileName);
-    if (gVerbose) {
-        printf("Shell: %s\n", command.string());
-    }
+    pid_t pid = fork();
+    if (pid < 0) {
+        int err = errno;
+        ALOGW("fork() failed: %s", strerror(err));
+        return -err;
+    } else if (pid > 0) {
+        // parent; wait for the child, mostly to make the verbose-mode output
+        // look right, but also to check for and log failures
+        int status;
+        pid_t actualPid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
+        if (actualPid != pid) {
+            ALOGW("waitpid() returned %d (errno=%d)", actualPid, errno);
+        } else if (status != 0) {
+            ALOGW("'am broadcast' exited with status=%d", status);
+        } else {
+            ALOGV("'am broadcast' exited successfully");
+        }
+    } else {
+        const char* kCommand = "/system/bin/am";
 
-    // TODO: for non-verbose mode we should suppress stdout
-    int status = system(command.string());
-    if (status < 0) {
-        fprintf(stderr, "Unable to fork shell for media scanner broadcast\n");
-        return UNKNOWN_ERROR;
-    } else if (status != 0) {
-        fprintf(stderr, "am command failed (status=%d): '%s'\n",
-                status, command.string());
-        return UNKNOWN_ERROR;
+        // child; we're single-threaded, so okay to alloc
+        String8 fileUrl("file://");
+        fileUrl.append(fileName);
+        const char* const argv[] = {
+                kCommand,
+                "broadcast",
+                "-a",
+                "android.intent.action.MEDIA_SCANNER_SCAN_FILE",
+                "-d",
+                fileUrl.string(),
+                NULL
+        };
+        if (gVerbose) {
+            printf("Executing:");
+            for (int i = 0; argv[i] != NULL; i++) {
+                printf(" %s", argv[i]);
+            }
+            putchar('\n');
+        } else {
+            // non-verbose, suppress 'am' output
+            ALOGV("closing stdout/stderr in child");
+            int fd = open("/dev/null", O_WRONLY);
+            if (fd >= 0) {
+                dup2(fd, STDOUT_FILENO);
+                dup2(fd, STDERR_FILENO);
+                close(fd);
+            }
+        }
+        execv(kCommand, const_cast<char* const*>(argv));
+        ALOGE("execv(%s) failed: %s\n", kCommand, strerror(errno));
+        exit(1);
     }
     return NO_ERROR;
 }
diff --git a/include/media/IHDCP.h b/include/media/IHDCP.h
index 54fefa3..352561e 100644
--- a/include/media/IHDCP.h
+++ b/include/media/IHDCP.h
@@ -46,6 +46,17 @@
     // Request to shutdown the active HDCP session.
     virtual status_t shutdownAsync() = 0;
 
+    // Returns the capability bitmask of this HDCP session.
+    // Possible return values (please refer to HDCAPAPI.h):
+    //   HDCP_CAPS_ENCRYPT: mandatory, meaning the HDCP module can encrypt
+    //   from an input byte-array buffer to an output byte-array buffer
+    //   HDCP_CAPS_ENCRYPT_NATIVE: the HDCP module supports encryption from
+    //   a native buffer to an output byte-array buffer. The format of the
+    //   input native buffer is specific to vendor's encoder implementation.
+    //   It is the same format as that used by the encoder when
+    //   "storeMetaDataInBuffers" extension is enabled on its output port.
+    virtual uint32_t getCaps() = 0;
+
     // ENCRYPTION only:
     // Encrypt data according to the HDCP spec. "size" bytes of data are
     // available at "inData" (virtual address), "size" may not be a multiple
diff --git a/media/libmedia/IHDCP.cpp b/media/libmedia/IHDCP.cpp
index a46ff91..1cf987a 100644
--- a/media/libmedia/IHDCP.cpp
+++ b/media/libmedia/IHDCP.cpp
@@ -30,6 +30,7 @@
     HDCP_SET_OBSERVER,
     HDCP_INIT_ASYNC,
     HDCP_SHUTDOWN_ASYNC,
+    HDCP_GET_CAPS,
     HDCP_ENCRYPT,
     HDCP_ENCRYPT_NATIVE,
     HDCP_DECRYPT,
@@ -85,6 +86,13 @@
         return reply.readInt32();
     }
 
+    virtual uint32_t getCaps() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IHDCP::getInterfaceDescriptor());
+        remote()->transact(HDCP_GET_CAPS, data, &reply);
+        return reply.readInt32();
+    }
+
     virtual status_t encrypt(
             const void *inData, size_t size, uint32_t streamCTR,
             uint64_t *outInputCTR, void *outData) {
@@ -222,6 +230,14 @@
             return OK;
         }
 
+        case HDCP_GET_CAPS:
+        {
+            CHECK_INTERFACE(IHDCP, data, reply);
+
+            reply->writeInt32(getCaps());
+            return OK;
+        }
+
         case HDCP_ENCRYPT:
         {
             size_t size = data.readInt32();
diff --git a/media/libmediaplayerservice/HDCP.cpp b/media/libmediaplayerservice/HDCP.cpp
index 8a3188c..c2ac1a3 100644
--- a/media/libmediaplayerservice/HDCP.cpp
+++ b/media/libmediaplayerservice/HDCP.cpp
@@ -100,6 +100,20 @@
     return mHDCPModule->shutdownAsync();
 }
 
+uint32_t HDCP::getCaps() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mHDCPModule == NULL) {
+        return NO_INIT;
+    }
+
+    // TO-DO:
+    // Only support HDCP_CAPS_ENCRYPT (byte-array to byte-array) for now.
+    // use mHDCPModule->getCaps() when the HDCP libraries get updated.
+    //return mHDCPModule->getCaps();
+    return HDCPModule::HDCP_CAPS_ENCRYPT;
+}
+
 status_t HDCP::encrypt(
         const void *inData, size_t size, uint32_t streamCTR,
         uint64_t *outInputCTR, void *outData) {
diff --git a/media/libmediaplayerservice/HDCP.h b/media/libmediaplayerservice/HDCP.h
index c60c2e0..26ddc86 100644
--- a/media/libmediaplayerservice/HDCP.h
+++ b/media/libmediaplayerservice/HDCP.h
@@ -30,6 +30,7 @@
     virtual status_t setObserver(const sp<IHDCPObserver> &observer);
     virtual status_t initAsync(const char *host, unsigned port);
     virtual status_t shutdownAsync();
+    virtual uint32_t getCaps();
 
     virtual status_t encrypt(
             const void *inData, size_t size, uint32_t streamCTR,
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index 0aa4ee5..286ea13 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -939,7 +939,8 @@
     if (isVideo) {
         format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
         format->setInt32("store-metadata-in-buffers", true);
-        format->setInt32("store-metadata-in-buffers-output", (mHDCP != NULL));
+        format->setInt32("store-metadata-in-buffers-output", (mHDCP != NULL)
+                && (mHDCP->getCaps() & HDCPModule::HDCP_CAPS_ENCRYPT_NATIVE));
         format->setInt32(
                 "color-format", OMX_COLOR_FormatAndroidOpaque);
         format->setInt32("profile-idc", profileIdc);
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index bf9bc71..fe16314 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -492,7 +492,7 @@
           case CAMERA_DEVICE_API_VERSION_1_0:
             ALOGE("Camera id %d uses HALv1, doesn't support ProCamera",
                   cameraId);
-            return -ENOTSUP;
+            return -EOPNOTSUPP;
             break;
           case CAMERA_DEVICE_API_VERSION_2_0:
           case CAMERA_DEVICE_API_VERSION_2_1:
@@ -570,7 +570,7 @@
         switch(deviceVersion) {
           case CAMERA_DEVICE_API_VERSION_1_0:
             ALOGW("Camera using old HAL version: %d", deviceVersion);
-            return -ENOTSUP;
+            return -EOPNOTSUPP;
            // TODO: don't allow 2.0  Only allow 2.1 and higher
           case CAMERA_DEVICE_API_VERSION_2_0:
           case CAMERA_DEVICE_API_VERSION_2_1: