Merge "ToneGenerator: fix stop/destroy concurrency" into jb-mr2-dev
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp
index 396b009..fec5461 100644
--- a/camera/ProCamera.cpp
+++ b/camera/ProCamera.cpp
@@ -103,7 +103,7 @@
     {
         Mutex::Autolock al(mWaitMutex);
         mMetadataReady = true;
-        mLatestMetadata = tmp;
+        mLatestMetadata = tmp; // make copy
         mWaitCondition.broadcast();
     }
 
@@ -312,8 +312,6 @@
     sp<ProCameraListener> listener = mListener;
     StreamInfo& stream = getStreamInfo(streamId);
 
-    CpuConsumer::LockedBuffer buf;
-
     if (listener.get() != NULL) {
         listener->onFrameAvailable(streamId, stream.cpuConsumer);
     }
@@ -421,7 +419,7 @@
 
     // Destructive: Subsequent calls return empty metadatas
     CameraMetadata tmp = mLatestMetadata;
-    mLatestMetadata.release();
+    mLatestMetadata.clear();
 
     return tmp;
 }
diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp
index ecc0854..2b5f3ad 100644
--- a/camera/tests/ProCameraTests.cpp
+++ b/camera/tests/ProCameraTests.cpp
@@ -587,14 +587,19 @@
     sp<ServiceListener> listener = new ServiceListener();
     EXPECT_OK(ProCamera::addServiceListener(listener));
 
-    ServiceListener::Status currentStatus = ServiceListener::STATUS_AVAILABLE;
+    ServiceListener::Status currentStatus;
+
+    // when subscribing a new listener,
+    // we immediately get a callback to the current status
+    while (listener->waitForStatusChange(/*out*/currentStatus) != OK);
+    EXPECT_EQ(ServiceListener::STATUS_PRESENT, currentStatus);
 
     dout << "Will now stream and resume infinitely..." << std::endl;
     while (true) {
 
-        if (currentStatus == ServiceListener::STATUS_AVAILABLE) {
+        if (currentStatus == ServiceListener::STATUS_PRESENT) {
 
-            EXPECT_OK(mCamera->createStream(mDisplayW, mDisplayH, mDisplayFmt,
+            ASSERT_OK(mCamera->createStream(mDisplayW, mDisplayH, mDisplayFmt,
                                             surface,
                                             &depthStreamId));
             EXPECT_NE(-1, depthStreamId);
@@ -613,12 +618,15 @@
         while (listener->waitForStatusChange(/*out*/stat) != OK);
 
         if (currentStatus != stat) {
-            if (stat == ServiceListener::STATUS_AVAILABLE) {
+            if (stat == ServiceListener::STATUS_PRESENT) {
                 dout << "Reconnecting to camera" << std::endl;
                 mCamera = ProCamera::connect(CAMERA_ID);
             } else if (stat == ServiceListener::STATUS_NOT_AVAILABLE) {
                 dout << "Disconnecting from camera" << std::endl;
                 mCamera->disconnect();
+            } else if (stat == ServiceListener::STATUS_NOT_PRESENT) {
+                dout << "Camera unplugged" << std::endl;
+                mCamera = NULL;
             } else {
                 dout << "Unknown status change "
                      << std::hex << stat << std::endl;
@@ -1021,6 +1029,9 @@
     // Consume two frames simultaneously. Unsynchronized by timestamps.
     for (int i = 0; i < REQUEST_COUNT; ++i) {
 
+        // Exhaust event queue so it doesn't keep growing
+        while (mListener->ReadEvent() != UNKNOWN);
+
         // Get the metadata
         EXPECT_OK(mCamera->waitForFrameMetadata());
         CameraMetadata meta = mCamera->consumeFrameMetadata();
@@ -1216,7 +1227,7 @@
     }
 
     EXPECT_OK(listener->waitForStatusChange(/*out*/stat));
-    EXPECT_EQ(ServiceListener::STATUS_AVAILABLE, stat);
+    EXPECT_EQ(ServiceListener::STATUS_PRESENT, stat);
 
     EXPECT_OK(ProCamera::removeServiceListener(listener));
 }
diff --git a/include/camera/ICameraServiceListener.h b/include/camera/ICameraServiceListener.h
index 88860dd..f2a11c2 100644
--- a/include/camera/ICameraServiceListener.h
+++ b/include/camera/ICameraServiceListener.h
@@ -38,9 +38,8 @@
      *     NOT_PRESENT         -> PRESENT
      *     NOT_PRESENT         -> ENUMERATING
      *     ENUMERATING         -> PRESENT
-     *     PRESENT             -> AVAILABLE
-     *     AVAILABLE           -> NOT_AVAILABLE
-     *     NOT_AVAILABLE       -> AVAILABLE
+     *     PRESENT             -> NOT_AVAILABLE
+     *     NOT_AVAILABLE       -> PRESENT
      *
      * A state will never immediately transition back to itself.
      */
@@ -48,15 +47,17 @@
         // Device physically unplugged
         STATUS_NOT_PRESENT      = CAMERA_DEVICE_STATUS_NOT_PRESENT,
         // Device physically has been plugged in
+        //  and the camera can be used exlusively
         STATUS_PRESENT          = CAMERA_DEVICE_STATUS_PRESENT,
         // Device physically has been plugged in
         //   but it will not be connect-able until enumeration is complete
         STATUS_ENUMERATING      = CAMERA_DEVICE_STATUS_ENUMERATING,
 
         // Camera can be used exclusively
-        STATUS_AVAILABLE        = 0x80000000,
+        STATUS_AVAILABLE        = STATUS_PRESENT, // deprecated, will be removed
+
         // Camera is in use by another app and cannot be used exclusively
-        STATUS_NOT_AVAILABLE,
+        STATUS_NOT_AVAILABLE    = 0x80000000,
 
         // Use to initialize variables only
         STATUS_UNKNOWN          = 0xFFFFFFFF,
diff --git a/media/libstagefright/wifi-display/source/Converter.cpp b/media/libstagefright/wifi-display/source/Converter.cpp
index d41e1e6..0a8462c 100644
--- a/media/libstagefright/wifi-display/source/Converter.cpp
+++ b/media/libstagefright/wifi-display/source/Converter.cpp
@@ -135,7 +135,9 @@
     return mNeedToManuallyPrependSPSPPS;
 }
 
-static int32_t getBitrate(const char *propName, int32_t defaultValue) {
+// static
+int32_t Converter::GetInt32Property(
+        const char *propName, int32_t defaultValue) {
     char val[PROPERTY_VALUE_MAX];
     if (property_get(propName, val, NULL)) {
         char *end;
@@ -185,8 +187,8 @@
 
     mOutputFormat->setString("mime", outputMIME.c_str());
 
-    int32_t audioBitrate = getBitrate("media.wfd.audio-bitrate", 128000);
-    int32_t videoBitrate = getBitrate("media.wfd.video-bitrate", 5000000);
+    int32_t audioBitrate = GetInt32Property("media.wfd.audio-bitrate", 128000);
+    int32_t videoBitrate = GetInt32Property("media.wfd.video-bitrate", 5000000);
     mPrevVideoBitrate = videoBitrate;
 
     ALOGI("using audio bitrate of %d bps, video bitrate of %d bps",
@@ -622,20 +624,6 @@
 }
 
 status_t Converter::doMoreWork() {
-#if 0
-    if (mIsVideo) {
-        int32_t videoBitrate = getBitrate("media.wfd.video-bitrate", 5000000);
-        if (videoBitrate != mPrevVideoBitrate) {
-            sp<AMessage> params = new AMessage;
-
-            params->setInt32("videoBitrate", videoBitrate);
-            mEncoder->setParameters(params);
-
-            mPrevVideoBitrate = videoBitrate;
-        }
-    }
-#endif
-
     status_t err;
 
     for (;;) {
diff --git a/media/libstagefright/wifi-display/source/Converter.h b/media/libstagefright/wifi-display/source/Converter.h
index 538f10a..ba297c4 100644
--- a/media/libstagefright/wifi-display/source/Converter.h
+++ b/media/libstagefright/wifi-display/source/Converter.h
@@ -73,6 +73,8 @@
     int32_t getVideoBitrate() const;
     void setVideoBitrate(int32_t bitrate);
 
+    static int32_t GetInt32Property(const char *propName, int32_t defaultValue);
+
 protected:
     virtual ~Converter();
     virtual void onMessageReceived(const sp<AMessage> &msg);
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index 68aa9cb..715d0b5 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -27,6 +27,7 @@
 #include "WifiDisplaySource.h"
 
 #include <binder/IServiceManager.h>
+#include <cutils/properties.h>
 #include <media/IHDCP.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
@@ -66,6 +67,7 @@
     bool isAudio() const;
 
     const sp<Converter> &converter() const;
+    const sp<RepeaterSource> &repeaterSource() const;
 
     ssize_t mediaSenderTrackIndex() const;
     void setMediaSenderTrackIndex(size_t index);
@@ -171,6 +173,11 @@
     return mConverter;
 }
 
+const sp<RepeaterSource> &
+WifiDisplaySource::PlaybackSession::Track::repeaterSource() const {
+    return mRepeaterSource;
+}
+
 ssize_t WifiDisplaySource::PlaybackSession::Track::mediaSenderTrackIndex() const {
     CHECK_GE(mMediaSenderTrackIndex, 0);
     return mMediaSenderTrackIndex;
@@ -663,27 +670,67 @@
     if (mVideoTrackIndex >= 0) {
         const sp<Track> &videoTrack = mTracks.valueFor(mVideoTrackIndex);
         sp<Converter> converter = videoTrack->converter();
+
         if (converter != NULL) {
-            int32_t videoBitrate = converter->getVideoBitrate();
+            int32_t videoBitrate =
+                Converter::GetInt32Property("media.wfd.video-bitrate", -1);
 
-            if (avgLatencyUs > 300000ll) {
-                videoBitrate *= 0.6;
+            char val[PROPERTY_VALUE_MAX];
+            if (videoBitrate < 0
+                    && property_get("media.wfd.video-bitrate", val, NULL)
+                    && !strcasecmp("adaptive", val)) {
+                videoBitrate = converter->getVideoBitrate();
 
-                if (videoBitrate < 500000) {
-                    videoBitrate = 500000;  // cap at 500kbit/sec
-                }
-            } else if (avgLatencyUs < 100000ll) {
-                videoBitrate *= 1.1;
-
-                if (videoBitrate > 10000000) {
-                    videoBitrate = 10000000;  // cap at 10Mbit/sec
+                if (avgLatencyUs > 300000ll) {
+                    videoBitrate *= 0.6;
+                } else if (avgLatencyUs < 100000ll) {
+                    videoBitrate *= 1.1;
                 }
             }
 
-            if (videoBitrate != converter->getVideoBitrate()) {
-                ALOGI("setting video bitrate to %d bps", videoBitrate);
+            if (videoBitrate > 0) {
+                if (videoBitrate < 500000) {
+                    videoBitrate = 500000;
+                } else if (videoBitrate > 10000000) {
+                    videoBitrate = 10000000;
+                }
 
-                converter->setVideoBitrate(videoBitrate);
+                if (videoBitrate != converter->getVideoBitrate()) {
+                    ALOGI("setting video bitrate to %d bps", videoBitrate);
+
+                    converter->setVideoBitrate(videoBitrate);
+                }
+            }
+        }
+
+        sp<RepeaterSource> repeaterSource = videoTrack->repeaterSource();
+        if (repeaterSource != NULL) {
+            double rateHz =
+                Converter::GetInt32Property(
+                        "media.wfd.video-framerate", -1);
+
+            if (rateHz < 0.0) {
+                rateHz = repeaterSource->getFrameRate();
+
+                if (avgLatencyUs > 300000ll) {
+                    rateHz *= 0.9;
+                } else if (avgLatencyUs < 200000ll) {
+                    rateHz *= 1.1;
+                }
+            }
+
+            if (rateHz > 0) {
+                if (rateHz < 5.0) {
+                    rateHz = 5.0;
+                } else if (rateHz > 30.0) {
+                    rateHz = 30.0;
+                }
+
+                if (rateHz != repeaterSource->getFrameRate()) {
+                    ALOGI("setting frame rate to %.2f Hz", rateHz);
+
+                    repeaterSource->setFrameRate(rateHz);
+                }
             }
         }
     }
diff --git a/media/libstagefright/wifi-display/source/RepeaterSource.cpp b/media/libstagefright/wifi-display/source/RepeaterSource.cpp
index 72be927..cc8dee3 100644
--- a/media/libstagefright/wifi-display/source/RepeaterSource.cpp
+++ b/media/libstagefright/wifi-display/source/RepeaterSource.cpp
@@ -27,6 +27,25 @@
     CHECK(!mStarted);
 }
 
+double RepeaterSource::getFrameRate() const {
+    return mRateHz;
+}
+
+void RepeaterSource::setFrameRate(double rateHz) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (rateHz == mRateHz) {
+        return;
+    }
+
+    if (mStartTimeUs >= 0ll) {
+        int64_t nextTimeUs = mStartTimeUs + (mFrameCount * 1000000ll) / mRateHz;
+        mStartTimeUs = nextTimeUs;
+        mFrameCount = 0;
+    }
+    mRateHz = rateHz;
+}
+
 status_t RepeaterSource::start(MetaData *params) {
     CHECK(!mStarted);
 
diff --git a/media/libstagefright/wifi-display/source/RepeaterSource.h b/media/libstagefright/wifi-display/source/RepeaterSource.h
index 146af32..8d414fd 100644
--- a/media/libstagefright/wifi-display/source/RepeaterSource.h
+++ b/media/libstagefright/wifi-display/source/RepeaterSource.h
@@ -28,6 +28,9 @@
     // send updates in a while, this is its wakeup call.
     void wakeUp();
 
+    double getFrameRate() const;
+    void setFrameRate(double rateHz);
+
 protected:
     virtual ~RepeaterSource();
 
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 5a6a3c8..2db5224 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -66,6 +66,20 @@
     return IPCThreadState::self()->getCallingUid();
 }
 
+extern "C" {
+static void camera_device_status_change(
+        const struct camera_module_callbacks* callbacks,
+        int camera_id,
+        int new_status) {
+    sp<CameraService> cs = const_cast<CameraService*>(
+                                static_cast<const CameraService*>(callbacks));
+
+    cs->onDeviceStatusChanged(
+        camera_id,
+        new_status);
+}
+} // extern "C"
+
 // ----------------------------------------------------------------------------
 
 // This is ugly and only safe if we never re-create the CameraService, but
@@ -79,8 +93,10 @@
     gCameraService = this;
 
     for (size_t i = 0; i < MAX_CAMERAS; ++i) {
-        mStatusList[i] = ICameraServiceListener::STATUS_AVAILABLE;
+        mStatusList[i] = ICameraServiceListener::STATUS_PRESENT;
     }
+
+    this->camera_device_status_change = android::camera_device_status_change;
 }
 
 void CameraService::onFirstRef()
@@ -105,6 +121,11 @@
         for (int i = 0; i < mNumberOfCameras; i++) {
             setCameraFree(i);
         }
+
+        if (mModule->common.module_api_version >=
+                CAMERA_MODULE_API_VERSION_2_1) {
+            mModule->set_callbacks(this);
+        }
     }
 }
 
@@ -118,6 +139,67 @@
     gCameraService = NULL;
 }
 
+void CameraService::onDeviceStatusChanged(int cameraId,
+                                          int newStatus)
+{
+    ALOGI("%s: Status changed for cameraId=%d, newStatus=%d", __FUNCTION__,
+          cameraId, newStatus);
+
+    if (cameraId < 0 || cameraId >= MAX_CAMERAS) {
+        ALOGE("%s: Bad camera ID %d", __FUNCTION__, cameraId);
+        return;
+    }
+
+    if ((int)getStatus(cameraId) == newStatus) {
+        ALOGE("%s: State transition to the same status 0x%x not allowed",
+              __FUNCTION__, (uint32_t)newStatus);
+        return;
+    }
+
+    /* don't do this in updateStatus
+       since it is also called from connect and we could get into a deadlock */
+    if (newStatus == CAMERA_DEVICE_STATUS_NOT_PRESENT) {
+        Vector<sp<BasicClient> > clientsToDisconnect;
+        {
+           Mutex::Autolock al(mServiceLock);
+
+           /* Find all clients that we need to disconnect */
+           sp<Client> client = mClient[cameraId].promote();
+           if (client.get() != NULL) {
+               clientsToDisconnect.push_back(client);
+           }
+
+           int i = cameraId;
+           for (size_t j = 0; j < mProClientList[i].size(); ++j) {
+               sp<ProClient> cl = mProClientList[i][j].promote();
+               if (cl != NULL) {
+                   clientsToDisconnect.push_back(cl);
+               }
+           }
+        }
+
+        /* now disconnect them. don't hold the lock
+           or we can get into a deadlock */
+
+        for (size_t i = 0; i < clientsToDisconnect.size(); ++i) {
+            sp<BasicClient> client = clientsToDisconnect[i];
+
+            client->disconnect();
+            /**
+             * The remote app will no longer be able to call methods on the
+             * client since the client PID will be reset to 0
+             */
+        }
+
+        ALOGV("%s: After unplug, disconnected %d clients",
+              __FUNCTION__, clientsToDisconnect.size());
+    }
+
+    updateStatus(
+            static_cast<ICameraServiceListener::Status>(newStatus), cameraId);
+
+}
+
 int32_t CameraService::getNumberOfCameras() {
     return mNumberOfCameras;
 }
@@ -212,6 +294,19 @@
         return false;
     }
 
+    ICameraServiceListener::Status currentStatus = getStatus(cameraId);
+    if (currentStatus == ICameraServiceListener::STATUS_NOT_PRESENT) {
+        ALOGI("Camera is not plugged in,"
+               " connect X (pid %d) rejected", callingPid);
+        return false;
+    } else if (currentStatus == ICameraServiceListener::STATUS_ENUMERATING) {
+        ALOGI("Camera is enumerating,"
+               " connect X (pid %d) rejected", callingPid);
+        return false;
+    }
+    // Else don't check for STATUS_NOT_AVAILABLE.
+    //  -- It's done implicitly in canConnectUnsafe /w the mBusy array
+
     return true;
 }
 
@@ -293,6 +388,7 @@
         // If there are other non-exclusive users of the camera,
         //  this will tear them down before we can reuse the camera
         if (isValidCameraId(cameraId)) {
+            // transition from PRESENT -> NOT_AVAILABLE
             updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE,
                          cameraId);
         }
@@ -321,7 +417,8 @@
 
         if (!connectFinishUnsafe(client, client->asBinder())) {
             // this is probably not recoverable.. maybe the client can try again
-            updateStatus(ICameraServiceListener::STATUS_AVAILABLE, cameraId);
+            // OK: we can only get here if we were originally in PRESENT state
+            updateStatus(ICameraServiceListener::STATUS_PRESENT, cameraId);
 
             return NULL;
         }
@@ -429,6 +526,15 @@
 
     mListenerList.push_back(listener);
 
+    /* Immediately signal current status to this listener only */
+    {
+        Mutex::Autolock m(mStatusMutex) ;
+        int numCams = getNumberOfCameras();
+        for (int i = 0; i < numCams; ++i) {
+            listener->onStatusChanged(mStatusList[i], i);
+        }
+    }
+
     return OK;
 }
 status_t CameraService::removeListener(
@@ -719,6 +825,8 @@
 
 void CameraService::BasicClient::disconnect() {
     mCameraService->removeClientByRemote(mRemoteBinder);
+    // client shouldn't be able to call into us anymore
+    mClientPid = 0;
 }
 
 status_t CameraService::BasicClient::startCameraOps() {
@@ -816,7 +924,7 @@
 void CameraService::Client::disconnect() {
     BasicClient::disconnect();
     mCameraService->setCameraFree(mCameraId);
-    mCameraService->updateStatus(ICameraServiceListener::STATUS_AVAILABLE,
+    mCameraService->updateStatus(ICameraServiceListener::STATUS_PRESENT,
                                  mCameraId);
 }
 
@@ -1017,6 +1125,16 @@
         ALOGV("%s: Status has changed for camera ID %d from 0x%x to 0x%x",
               __FUNCTION__, cameraId, (uint32_t)oldStatus, (uint32_t)status);
 
+        if (oldStatus == ICameraServiceListener::STATUS_NOT_PRESENT &&
+            (status != ICameraServiceListener::STATUS_PRESENT &&
+             status != ICameraServiceListener::STATUS_ENUMERATING)) {
+
+            ALOGW("%s: From NOT_PRESENT can only transition into PRESENT"
+                  " or ENUMERATING", __FUNCTION__);
+            mStatusList[cameraId] = oldStatus;
+            return;
+        }
+
         /**
           * ProClients lose their exclusive lock.
           * - Done before the CameraClient can initialize the HAL device,
@@ -1041,4 +1159,14 @@
     }
 }
 
+ICameraServiceListener::Status CameraService::getStatus(int cameraId) const {
+    if (cameraId < 0 || cameraId >= MAX_CAMERAS) {
+        ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId);
+        return ICameraServiceListener::STATUS_UNKNOWN;
+    }
+
+    Mutex::Autolock al(mStatusMutex);
+    return mStatusList[cameraId];
+}
+
 }; // namespace android
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index c5e495f..8cb1691 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -45,7 +45,8 @@
 class CameraService :
     public BinderService<CameraService>,
     public BnCameraService,
-    public IBinder::DeathRecipient
+    public IBinder::DeathRecipient,
+    public camera_module_callbacks_t
 {
     friend class BinderService<CameraService>;
 public:
@@ -59,6 +60,11 @@
     virtual             ~CameraService();
 
     /////////////////////////////////////////////////////////////////////
+    // HAL Callbacks
+    virtual void        onDeviceStatusChanged(int cameraId,
+                                              int newStatus);
+
+    /////////////////////////////////////////////////////////////////////
     // ICameraService
     virtual int32_t     getNumberOfCameras();
     virtual status_t    getCameraInfo(int cameraId,
@@ -327,10 +333,14 @@
                         mListenerList;
 
     // guard only mStatusList and the broadcasting of ICameraServiceListener
-    Mutex               mStatusMutex;
+    mutable Mutex       mStatusMutex;
     ICameraServiceListener::Status
                         mStatusList[MAX_CAMERAS];
 
+    // Read the current status (locks mStatusMutex)
+    ICameraServiceListener::Status
+                        getStatus(int cameraId) const;
+
     // Broadcast the new status if it changed (locks the service mutex)
     void                updateStatus(
                             ICameraServiceListener::Status status,
diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp
index 2332b3e..f60749d 100644
--- a/services/medialog/MediaLogService.cpp
+++ b/services/medialog/MediaLogService.cpp
@@ -19,6 +19,7 @@
 
 #include <sys/mman.h>
 #include <utils/Log.h>
+#include <binder/PermissionCache.h>
 #include <media/nbaio/NBLog.h>
 #include <private/android_filesystem_config.h>
 #include "MediaLogService.h"
@@ -55,6 +56,14 @@
 
 status_t MediaLogService::dump(int fd, const Vector<String16>& args)
 {
+    // FIXME merge with similar but not identical code at services/audioflinger/ServiceUtilities.cpp
+    static const String16 sDump("android.permission.DUMP");
+    if (!(IPCThreadState::self()->getCallingUid() == AID_MEDIA ||
+            PermissionCache::checkCallingPermission(sDump))) {
+        fdprintf(fd, "Permission denied.\n");
+        return NO_ERROR;
+    }
+
     Vector<NamedReader> namedReaders;
     {
         Mutex::Autolock _l(mLock);