CameraService and Stagefright: Support AppOps

Camera:
- Signal to AppOpsService when camera usage starts and stops
- Listen to permissions revocations and act on them
- Currently just kill camera connection when permissions lost

Stagefright:
- Pass on client name, UID to camera as needed

Bug: 8181262
Change-Id: I9e33c9d05e9daa77dbb2d795045d08eb887ec8f0
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index be395ba..d8dc2a5 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -19,6 +19,7 @@
 #define LOG_TAG "Camera"
 #include <utils/Log.h>
 #include <utils/threads.h>
+#include <utils/String16.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/IMemory.h>
@@ -116,14 +117,15 @@
     return cs->getCameraInfo(cameraId, cameraInfo);
 }
 
-sp<Camera> Camera::connect(int cameraId)
+sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
+        int clientUid)
 {
     ALOGV("connect");
     sp<Camera> c = new Camera();
     sp<ICameraClient> cl = c;
     const sp<ICameraService>& cs = getCameraService();
     if (cs != 0) {
-        c->mCamera = cs->connect(cl, cameraId);
+        c->mCamera = cs->connect(cl, cameraId, clientPackageName, clientUid);
     }
     if (c->mCamera != 0) {
         c->mCamera->asBinder()->linkToDeath(c);
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index 8237c66..fdf20ff 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -56,12 +56,15 @@
     }
 
     // connect to camera service
-    virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId)
+    virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId,
+                                const String16 &clientPackageName, int clientUid)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
         data.writeStrongBinder(cameraClient->asBinder());
         data.writeInt32(cameraId);
+        data.writeString16(clientPackageName);
+        data.writeInt32(clientUid);
         remote()->transact(BnCameraService::CONNECT, data, &reply);
         return interface_cast<ICamera>(reply.readStrongBinder());
     }
@@ -103,8 +106,13 @@
         } break;
         case CONNECT: {
             CHECK_INTERFACE(ICameraService, data, reply);
-            sp<ICameraClient> cameraClient = interface_cast<ICameraClient>(data.readStrongBinder());
-            sp<ICamera> camera = connect(cameraClient, data.readInt32());
+            sp<ICameraClient> cameraClient =
+                    interface_cast<ICameraClient>(data.readStrongBinder());
+            int32_t cameraId = data.readInt32();
+            const String16 clientName = data.readString16();
+            int32_t clientUid = data.readInt32();
+            sp<ICamera> camera = connect(cameraClient, cameraId,
+                    clientName, clientUid);
             reply->writeStrongBinder(camera->asBinder());
             return NO_ERROR;
         } break;
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 45c3f7b..b7a40c2 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -264,7 +264,8 @@
 #endif
 
 #if 0
-    CameraSource *source = CameraSource::Create();
+    CameraSource *source = CameraSource::Create(
+            String16(argv[0], strlen(argv[0])));
     source->start();
 
     printf("source = %p\n", source);
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index 8b87de6..be2b7f4 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -53,6 +53,7 @@
 class Surface;
 class Mutex;
 class String8;
+class String16;
 
 // ref-counted object for callbacks
 class CameraListener: virtual public RefBase
@@ -67,12 +68,19 @@
 class Camera : public BnCameraClient, public IBinder::DeathRecipient
 {
 public:
+    enum {
+        USE_CALLING_UID = -1
+    };
+
             // construct a camera client from an existing remote
     static  sp<Camera>  create(const sp<ICamera>& camera);
     static  int32_t     getNumberOfCameras();
     static  status_t    getCameraInfo(int cameraId,
                                       struct CameraInfo* cameraInfo);
-    static  sp<Camera>  connect(int cameraId);
+    static  sp<Camera>  connect(int cameraId,
+                                const String16& clientPackageName,
+                                int clientUid);
+
             virtual     ~Camera();
             void        init();
 
diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h
index 11d7b65..aa64243 100644
--- a/include/camera/ICameraService.h
+++ b/include/camera/ICameraService.h
@@ -37,18 +37,28 @@
         CONNECT_PRO
     };
 
+    enum {
+        USE_CALLING_UID = -1
+    };
+
 public:
     DECLARE_META_INTERFACE(CameraService);
 
     virtual int32_t         getNumberOfCameras() = 0;
     virtual status_t        getCameraInfo(int cameraId,
                                           struct CameraInfo* cameraInfo) = 0;
-    virtual sp<ICamera>     connect(const sp<ICameraClient>& cameraClient,
-                                    int cameraId) = 0;
+    /**
+     * clientPackageName and clientUid are used for permissions checking.  if
+     * clientUid == USE_CALLING_UID, then the calling UID is used instead. Only
+     * trusted callers can set a clientUid other than USE_CALLING_UID.
+     */
+    virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient,
+            int cameraId,
+            const String16& clientPackageName,
+            int clientUid) = 0;
 
-    virtual sp<IProCameraUser>
-                            connect(const sp<IProCameraCallbacks>& cameraCb,
-                                    int cameraId) = 0;
+    virtual sp<IProCameraUser> connect(const sp<IProCameraCallbacks>& cameraCb,
+            int cameraId) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index 54af0d3..8d7f11d 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -47,6 +47,7 @@
     virtual status_t setVideoFrameRate(int frames_per_second) = 0;
     virtual status_t setParameters(const String8& params) = 0;
     virtual status_t setListener(const sp<IMediaRecorderClient>& listener) = 0;
+    virtual status_t setClientName(const String16& clientName) = 0;
     virtual status_t prepare() = 0;
     virtual status_t getMaxAmplitude(int* max) = 0;
     virtual status_t start() = 0;
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
index 803bc64..8dd40d2 100644
--- a/include/media/MediaRecorderBase.h
+++ b/include/media/MediaRecorderBase.h
@@ -48,6 +48,7 @@
     virtual status_t setOutputFileAuxiliary(int fd) {return INVALID_OPERATION;}
     virtual status_t setParameters(const String8& params) = 0;
     virtual status_t setListener(const sp<IMediaRecorderClient>& listener) = 0;
+    virtual status_t setClientName(const String16& clientName) = 0;
     virtual status_t prepare() = 0;
     virtual status_t start() = 0;
     virtual status_t stop() = 0;
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index da6b507..3b33479 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -219,6 +219,7 @@
     status_t    setVideoFrameRate(int frames_per_second);
     status_t    setParameters(const String8& params);
     status_t    setListener(const sp<MediaRecorderListener>& listener);
+    status_t    setClientName(const String16& clientName);
     status_t    prepare();
     status_t    getMaxAmplitude(int* max);
     status_t    start();
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index 6d6b8a9..cf38b14 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -25,6 +25,7 @@
 #include <camera/CameraParameters.h>
 #include <utils/List.h>
 #include <utils/RefBase.h>
+#include <utils/String16.h>
 
 namespace android {
 
@@ -39,9 +40,11 @@
      * settings (such as video size, frame rate, color format, etc)
      * from the default camera.
      *
+     * @param clientName The package/process name of the client application.
+     *    This is used for permissions checking.
      * @return NULL on error.
      */
-    static CameraSource *Create();
+    static CameraSource *Create(const String16 &clientName);
 
     /**
      * Factory method to create a new CameraSource.
@@ -52,7 +55,11 @@
      *
      * @param cameraId the id of the camera that the source will connect
      *          to if camera is NULL; otherwise ignored.
-     *
+     * @param clientName the package/process name of the camera-using
+     *          application if camera is NULL; otherwise ignored. Used for
+     *          permissions checking.
+     * @param clientUid the UID of the camera-using application if camera is
+     *          NULL; otherwise ignored. Used for permissions checking.
      * @param videoSize the dimension (in pixels) of the video frame
      * @param frameRate the target frames per second
      * @param surface the preview surface for display where preview
@@ -71,6 +78,8 @@
     static CameraSource *CreateFromCamera(const sp<ICamera> &camera,
                                           const sp<ICameraRecordingProxy> &proxy,
                                           int32_t cameraId,
+                                          const String16& clientName,
+                                          uid_t clientUid,
                                           Size videoSize,
                                           int32_t frameRate,
                                           const sp<Surface>& surface,
@@ -158,7 +167,7 @@
     int64_t mTimeBetweenFrameCaptureUs;
 
     CameraSource(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
-                 int32_t cameraId,
+                 int32_t cameraId, const String16& clientName, uid_t clientUid,
                  Size videoSize, int32_t frameRate,
                  const sp<Surface>& surface,
                  bool storeMetaDataInVideoBuffers);
@@ -198,17 +207,20 @@
 
 
     status_t init(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
-                  int32_t cameraId, Size videoSize, int32_t frameRate,
-                  bool storeMetaDataInVideoBuffers);
+                  int32_t cameraId, const String16& clientName, uid_t clientUid,
+                  Size videoSize, int32_t frameRate, bool storeMetaDataInVideoBuffers);
 
     status_t initWithCameraAccess(
                   const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
-                  int32_t cameraId, Size videoSize, int32_t frameRate,
-                  bool storeMetaDataInVideoBuffers);
+                  int32_t cameraId, const String16& clientName, uid_t clientUid,
+                  Size videoSize, int32_t frameRate, bool storeMetaDataInVideoBuffers);
 
     status_t isCameraAvailable(const sp<ICamera>& camera,
                                const sp<ICameraRecordingProxy>& proxy,
-                               int32_t cameraId);
+                               int32_t cameraId,
+                               const String16& clientName,
+                               uid_t clientUid);
+
     status_t isCameraColorFormatSupported(const CameraParameters& params);
     status_t configureCamera(CameraParameters* params,
                     int32_t width, int32_t height,
diff --git a/include/media/stagefright/CameraSourceTimeLapse.h b/include/media/stagefright/CameraSourceTimeLapse.h
index 0936da2..774772b 100644
--- a/include/media/stagefright/CameraSourceTimeLapse.h
+++ b/include/media/stagefright/CameraSourceTimeLapse.h
@@ -22,6 +22,7 @@
 
 #include <utils/RefBase.h>
 #include <utils/threads.h>
+#include <utils/String16.h>
 
 namespace android {
 
@@ -35,6 +36,8 @@
         const sp<ICamera> &camera,
         const sp<ICameraRecordingProxy> &proxy,
         int32_t cameraId,
+        const String16& clientName,
+        uid_t clientUid,
         Size videoSize,
         int32_t videoFrameRate,
         const sp<Surface>& surface,
@@ -108,6 +111,8 @@
         const sp<ICamera> &camera,
         const sp<ICameraRecordingProxy> &proxy,
         int32_t cameraId,
+        const String16& clientName,
+        uid_t clientUid,
         Size videoSize,
         int32_t videoFrameRate,
         const sp<Surface>& surface,
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index fdbc747..c935d97 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -51,7 +51,8 @@
     SET_PARAMETERS,
     SET_PREVIEW_SURFACE,
     SET_CAMERA,
-    SET_LISTENER
+    SET_LISTENER,
+    SET_CLIENT_NAME
 };
 
 class BpMediaRecorder: public BpInterface<IMediaRecorder>
@@ -217,6 +218,16 @@
         return reply.readInt32();
     }
 
+    status_t setClientName(const String16& clientName)
+    {
+        ALOGV("setClientName(%s)", String8(clientName).string());
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeString16(clientName);
+        remote()->transact(SET_CLIENT_NAME, data, &reply);
+        return reply.readInt32();
+    }
+
     status_t prepare()
     {
         ALOGV("prepare");
@@ -423,6 +434,12 @@
             reply->writeInt32(setListener(listener));
             return NO_ERROR;
         } break;
+        case SET_CLIENT_NAME: {
+            ALOGV("SET_CLIENT_NAME");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            reply->writeInt32(setClientName(data.readString16()));
+            return NO_ERROR;
+        }
         case SET_PREVIEW_SURFACE: {
             ALOGV("SET_PREVIEW_SURFACE");
             CHECK_INTERFACE(IMediaRecorder, data, reply);
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 660b1b2..3ac98cc 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -656,6 +656,27 @@
     return NO_ERROR;
 }
 
+status_t MediaRecorder::setClientName(const String16& clientName)
+{
+    ALOGV("setClientName");
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    bool isInvalidState = (mCurrentState &
+                           (MEDIA_RECORDER_PREPARED |
+                            MEDIA_RECORDER_RECORDING |
+                            MEDIA_RECORDER_ERROR));
+    if (isInvalidState) {
+        ALOGE("setClientName is called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    mMediaRecorder->setClientName(clientName);
+
+    return NO_ERROR;
+}
+
 void MediaRecorder::notify(int msg, int ext1, int ext2)
 {
     ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index c6d8b76..a52b238 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -99,7 +99,7 @@
         return PERMISSION_DENIED;
     }
     Mutex::Autolock lock(mLock);
-    if (mRecorder == NULL)	{
+    if (mRecorder == NULL)     {
         ALOGE("recorder is not initialized");
         return NO_INIT;
     }
@@ -325,6 +325,16 @@
     return mRecorder->setListener(listener);
 }
 
+status_t MediaRecorderClient::setClientName(const String16& clientName) {
+    ALOGV("setClientName(%s)", String8(clientName).string());
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        ALOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->setClientName(clientName);
+}
+
 status_t MediaRecorderClient::dump(int fd, const Vector<String16>& args) const {
     if (mRecorder != NULL) {
         return mRecorder->dump(fd, args);
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 5623917..bd0eaf1 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -46,6 +46,7 @@
     virtual     status_t   setParameters(const String8& params);
     virtual     status_t   setListener(
                               const sp<IMediaRecorderClient>& listener);
+    virtual     status_t   setClientName(const String16& clientName);
     virtual     status_t   prepare();
     virtual     status_t   getMaxAmplitude(int* max);
     virtual     status_t   start();
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 497dda6..f570856 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -730,6 +730,12 @@
     return OK;
 }
 
+status_t StagefrightRecorder::setClientName(const String16& clientName) {
+    mClientName = clientName;
+
+    return OK;
+}
+
 status_t StagefrightRecorder::prepare() {
     return OK;
 }
@@ -737,6 +743,8 @@
 status_t StagefrightRecorder::start() {
     CHECK_GE(mOutputFd, 0);
 
+    // Get UID here for permission checking
+    mClientUid = IPCThreadState::self()->getCallingUid();
     if (mWriter != NULL) {
         ALOGE("File writer is not avaialble");
         return UNKNOWN_ERROR;
@@ -1312,13 +1320,14 @@
         }
 
         mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera(
-                mCamera, mCameraProxy, mCameraId,
+                mCamera, mCameraProxy, mCameraId, mClientName, mClientUid,
                 videoSize, mFrameRate, mPreviewSurface,
                 mTimeBetweenTimeLapseFrameCaptureUs);
         *cameraSource = mCameraSourceTimeLapse;
     } else {
         *cameraSource = CameraSource::CreateFromCamera(
-                mCamera, mCameraProxy, mCameraId, videoSize, mFrameRate,
+                mCamera, mCameraProxy, mCameraId, mClientName, mClientUid,
+                videoSize, mFrameRate,
                 mPreviewSurface, true /*storeMetaDataInVideoBuffers*/);
     }
     mCamera.clear();
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 351efd4..fbe6fa6 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -56,6 +56,7 @@
     virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
     virtual status_t setParameters(const String8& params);
     virtual status_t setListener(const sp<IMediaRecorderClient>& listener);
+    virtual status_t setClientName(const String16& clientName);
     virtual status_t prepare();
     virtual status_t start();
     virtual status_t pause();
@@ -72,6 +73,8 @@
     sp<ICameraRecordingProxy> mCameraProxy;
     sp<Surface> mPreviewSurface;
     sp<IMediaRecorderClient> mListener;
+    String16 mClientName;
+    uid_t mClientUid;
     sp<MediaWriter> mWriter;
     int mOutputFd;
     sp<AudioSource> mAudioSourceNode;
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index efd7af7..f8557d0 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -121,13 +121,14 @@
     CHECK(!"Unknown color format");
 }
 
-CameraSource *CameraSource::Create() {
+CameraSource *CameraSource::Create(const String16 &clientName) {
     Size size;
     size.width = -1;
     size.height = -1;
 
     sp<ICamera> camera;
-    return new CameraSource(camera, NULL, 0, size, -1, NULL, false);
+    return new CameraSource(camera, NULL, 0, clientName, -1,
+            size, -1, NULL, false);
 }
 
 // static
@@ -135,14 +136,16 @@
     const sp<ICamera>& camera,
     const sp<ICameraRecordingProxy>& proxy,
     int32_t cameraId,
+    const String16& clientName,
+    uid_t clientUid,
     Size videoSize,
     int32_t frameRate,
     const sp<Surface>& surface,
     bool storeMetaDataInVideoBuffers) {
 
     CameraSource *source = new CameraSource(camera, proxy, cameraId,
-                    videoSize, frameRate, surface,
-                    storeMetaDataInVideoBuffers);
+            clientName, clientUid, videoSize, frameRate, surface,
+            storeMetaDataInVideoBuffers);
     return source;
 }
 
@@ -150,6 +153,8 @@
     const sp<ICamera>& camera,
     const sp<ICameraRecordingProxy>& proxy,
     int32_t cameraId,
+    const String16& clientName,
+    uid_t clientUid,
     Size videoSize,
     int32_t frameRate,
     const sp<Surface>& surface,
@@ -173,6 +178,7 @@
     mVideoSize.height = -1;
 
     mInitCheck = init(camera, proxy, cameraId,
+                    clientName, clientUid,
                     videoSize, frameRate,
                     storeMetaDataInVideoBuffers);
     if (mInitCheck != OK) releaseCamera();
@@ -184,10 +190,10 @@
 
 status_t CameraSource::isCameraAvailable(
     const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
-    int32_t cameraId) {
+    int32_t cameraId, const String16& clientName, uid_t clientUid) {
 
     if (camera == 0) {
-        mCamera = Camera::connect(cameraId);
+        mCamera = Camera::connect(cameraId, clientName, clientUid);
         if (mCamera == 0) return -EBUSY;
         mCameraFlags &= ~FLAGS_HOT_CAMERA;
     } else {
@@ -469,6 +475,8 @@
         const sp<ICamera>& camera,
         const sp<ICameraRecordingProxy>& proxy,
         int32_t cameraId,
+        const String16& clientName,
+        uid_t clientUid,
         Size videoSize,
         int32_t frameRate,
         bool storeMetaDataInVideoBuffers) {
@@ -476,7 +484,7 @@
     ALOGV("init");
     status_t err = OK;
     int64_t token = IPCThreadState::self()->clearCallingIdentity();
-    err = initWithCameraAccess(camera, proxy, cameraId,
+    err = initWithCameraAccess(camera, proxy, cameraId, clientName, clientUid,
                                videoSize, frameRate,
                                storeMetaDataInVideoBuffers);
     IPCThreadState::self()->restoreCallingIdentity(token);
@@ -487,13 +495,16 @@
         const sp<ICamera>& camera,
         const sp<ICameraRecordingProxy>& proxy,
         int32_t cameraId,
+        const String16& clientName,
+        uid_t clientUid,
         Size videoSize,
         int32_t frameRate,
         bool storeMetaDataInVideoBuffers) {
     ALOGV("initWithCameraAccess");
     status_t err = OK;
 
-    if ((err = isCameraAvailable(camera, proxy, cameraId)) != OK) {
+    if ((err = isCameraAvailable(camera, proxy, cameraId,
+            clientName, clientUid)) != OK) {
         ALOGE("Camera connection could not be established.");
         return err;
     }
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 26ce7ae..2ed2223 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -36,6 +36,8 @@
         const sp<ICamera> &camera,
         const sp<ICameraRecordingProxy> &proxy,
         int32_t cameraId,
+        const String16& clientName,
+        uid_t clientUid,
         Size videoSize,
         int32_t videoFrameRate,
         const sp<Surface>& surface,
@@ -43,6 +45,7 @@
 
     CameraSourceTimeLapse *source = new
             CameraSourceTimeLapse(camera, proxy, cameraId,
+                clientName, clientUid,
                 videoSize, videoFrameRate, surface,
                 timeBetweenFrameCaptureUs);
 
@@ -59,11 +62,14 @@
         const sp<ICamera>& camera,
         const sp<ICameraRecordingProxy>& proxy,
         int32_t cameraId,
+        const String16& clientName,
+        uid_t clientUid,
         Size videoSize,
         int32_t videoFrameRate,
         const sp<Surface>& surface,
         int64_t timeBetweenFrameCaptureUs)
-    : CameraSource(camera, proxy, cameraId, videoSize, videoFrameRate, surface, true),
+      : CameraSource(camera, proxy, cameraId, clientName, clientUid,
+                videoSize, videoFrameRate, surface, true),
       mTimeBetweenTimeLapseVideoFramesUs(1E6/videoFrameRate),
       mLastTimeLapseFrameRealTimestampUs(0),
       mSkipCurrentFrame(false) {
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index e8b3b7f..38d6949 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -40,12 +40,14 @@
 
 Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
         const sp<ICameraClient>& cameraClient,
+        const String16& clientPackageName,
         int cameraId,
         int cameraFacing,
         int clientPid,
+        uid_t clientUid,
         int servicePid):
-        Client(cameraService, cameraClient,
-                cameraId, cameraFacing, clientPid, servicePid),
+        Client(cameraService, cameraClient, clientPackageName,
+                cameraId, cameraFacing, clientPid, clientUid, servicePid),
         mSharedCameraClient(cameraClient),
         mParameters(cameraId, cameraFacing)
 {
@@ -73,6 +75,12 @@
     ALOGV("%s: Initializing client for camera %d", __FUNCTION__, mCameraId);
     status_t res;
 
+    // Verify ops permissions
+    res = startCameraOps();
+    if (res != OK) {
+        return res;
+    }
+
     res = mDevice->initialize(module);
     if (res != OK) {
         ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
@@ -741,8 +749,7 @@
 
     switch (state) {
         case Parameters::DISCONNECTED:
-            ALOGE("%s: Camera %d: Call before initialized",
-                    __FUNCTION__, mCameraId);
+            // Nothing to do.
             break;
         case Parameters::STOPPED:
         case Parameters::VIDEO_SNAPSHOT:
diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h
index a4d4478..173b65e 100644
--- a/services/camera/libcameraservice/Camera2Client.h
+++ b/services/camera/libcameraservice/Camera2Client.h
@@ -72,9 +72,11 @@
 
     Camera2Client(const sp<CameraService>& cameraService,
             const sp<ICameraClient>& cameraClient,
+            const String16& clientPackageName,
             int cameraId,
             int cameraFacing,
             int clientPid,
+            uid_t clientUid,
             int servicePid);
     virtual ~Camera2Client();
 
diff --git a/services/camera/libcameraservice/CameraClient.cpp b/services/camera/libcameraservice/CameraClient.cpp
index f67c9f4..90f8f40 100644
--- a/services/camera/libcameraservice/CameraClient.cpp
+++ b/services/camera/libcameraservice/CameraClient.cpp
@@ -35,9 +35,12 @@
 
 CameraClient::CameraClient(const sp<CameraService>& cameraService,
         const sp<ICameraClient>& cameraClient,
-        int cameraId, int cameraFacing, int clientPid, int servicePid):
-        Client(cameraService, cameraClient,
-                cameraId, cameraFacing, clientPid, servicePid)
+        const String16& clientPackageName,
+        int cameraId, int cameraFacing,
+        int clientPid, int clientUid,
+        int servicePid):
+        Client(cameraService, cameraClient, clientPackageName,
+                cameraId, cameraFacing, clientPid, clientUid, servicePid)
 {
     int callingPid = getCallingPid();
     LOG1("CameraClient::CameraClient E (pid %d, id %d)", callingPid, cameraId);
@@ -57,10 +60,17 @@
 
 status_t CameraClient::initialize(camera_module_t *module) {
     int callingPid = getCallingPid();
+    status_t res;
+
     LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);
 
+    // Verify ops permissions
+    res = startCameraOps();
+    if (res != OK) {
+        return res;
+    }
+
     char camera_device_name[10];
-    status_t res;
     snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);
 
     mHardware = new CameraHardwareInterface(camera_device_name);
diff --git a/services/camera/libcameraservice/CameraClient.h b/services/camera/libcameraservice/CameraClient.h
index 74829ce..00dc90c 100644
--- a/services/camera/libcameraservice/CameraClient.h
+++ b/services/camera/libcameraservice/CameraClient.h
@@ -53,9 +53,11 @@
     // Interface used by CameraService
     CameraClient(const sp<CameraService>& cameraService,
             const sp<ICameraClient>& cameraClient,
+            const String16& clientPackageName,
             int cameraId,
             int cameraFacing,
             int clientPid,
+            int clientUid,
             int servicePid);
     ~CameraClient();
 
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index eb8bc05..ec1c3f0 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -22,6 +22,7 @@
 #include <sys/types.h>
 #include <pthread.h>
 
+#include <binder/AppOpsManager.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/MemoryBase.h>
@@ -72,7 +73,7 @@
 static CameraService *gCameraService;
 
 CameraService::CameraService()
-:mSoundRef(0), mModule(0)
+    :mSoundRef(0), mModule(0)
 {
     ALOGI("CameraService started (pid=%d)", getpid());
     gCameraService = this;
@@ -155,10 +156,27 @@
 }
 
 sp<ICamera> CameraService::connect(
-        const sp<ICameraClient>& cameraClient, int cameraId) {
+        const sp<ICameraClient>& cameraClient,
+        int cameraId,
+        const String16& clientPackageName,
+        int clientUid) {
+
+    String8 clientName8(clientPackageName);
     int callingPid = getCallingPid();
 
-    LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);
+    LOG1("CameraService::connect E (pid %d \"%s\", id %d)", callingPid,
+            clientName8.string(), cameraId);
+
+    if (clientUid == USE_CALLING_UID) {
+        clientUid = getCallingUid();
+    } else {
+        // We only trust our own process to forward client UIDs
+        if (callingPid != getpid()) {
+            ALOGE("CameraService::connect X (pid %d) rejected (don't trust clientUid)",
+                    callingPid);
+            return NULL;
+        }
+    }
 
     if (!mModule) {
         ALOGE("Camera HAL module not loaded");
@@ -208,8 +226,10 @@
     would be fine
     */
     if (mBusy[cameraId]) {
-        ALOGW("CameraService::connect X (pid %d) rejected"
-                " (camera %d is still busy).", callingPid, cameraId);
+
+        ALOGW("CameraService::connect X (pid %d, \"%s\") rejected"
+                " (camera %d is still busy).", callingPid,
+                clientName8.string(), cameraId);
         return NULL;
     }
 
@@ -218,13 +238,15 @@
 
     switch(deviceVersion) {
       case CAMERA_DEVICE_API_VERSION_1_0:
-        client = new CameraClient(this, cameraClient, cameraId,
-                facing, callingPid, getpid());
+        client = new CameraClient(this, cameraClient,
+                clientPackageName, cameraId,
+                facing, callingPid, clientUid, getpid());
         break;
       case CAMERA_DEVICE_API_VERSION_2_0:
       case CAMERA_DEVICE_API_VERSION_2_1:
-        client = new Camera2Client(this, cameraClient, cameraId,
-                facing, callingPid, getpid());
+        client = new Camera2Client(this, cameraClient,
+                clientPackageName, cameraId,
+                facing, callingPid, clientUid, getpid());
         break;
       case -1:
         ALOGE("Invalid camera id %d", cameraId);
@@ -283,8 +305,8 @@
         break;
       case CAMERA_DEVICE_API_VERSION_2_0:
       case CAMERA_DEVICE_API_VERSION_2_1:
-        client = new ProCamera2Client(this, cameraCb, cameraId,
-                facing, callingPid, getpid());
+        client = new ProCamera2Client(this, cameraCb, String16(),
+                cameraId, facing, callingPid, USE_CALLING_UID, getpid());
         break;
       case -1:
         ALOGE("Invalid camera id %d", cameraId);
@@ -302,7 +324,8 @@
 
     cameraCb->asBinder()->linkToDeath(this);
 
-    LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId, getpid());
+    LOG1("CameraService::connectPro X (id %d, this pid is %d)", cameraId,
+            getpid());
     return client;
 
 
@@ -522,10 +545,15 @@
 
 CameraService::Client::Client(const sp<CameraService>& cameraService,
         const sp<ICameraClient>& cameraClient,
-        int cameraId, int cameraFacing, int clientPid, int servicePid) :
+        const String16& clientPackageName,
+        int cameraId, int cameraFacing,
+        int clientPid, uid_t clientUid,
+        int servicePid) :
         CameraService::BasicClient(cameraService, cameraClient->asBinder(),
-                                   cameraId, cameraFacing,
-                                   clientPid, servicePid)
+                clientPackageName,
+                cameraId, cameraFacing,
+                clientPid, clientUid,
+                servicePid)
 {
     int callingPid = getCallingPid();
     LOG1("Client::Client E (pid %d, id %d)", callingPid, cameraId);
@@ -534,6 +562,7 @@
 
     cameraService->setCameraBusy(cameraId);
     cameraService->loadSound();
+
     LOG1("Client::Client X (pid %d, id %d)", callingPid, cameraId);
 }
 
@@ -542,23 +571,27 @@
     mDestructionStarted = true;
 
     mCameraService->releaseSound();
-
+    finishCameraOps();
     // unconditionally disconnect. function is idempotent
     Client::disconnect();
 }
 
 CameraService::BasicClient::BasicClient(const sp<CameraService>& cameraService,
-                                   const sp<IBinder>& remoteCallback,
-                                   int cameraId, int cameraFacing,
-                                   int clientPid, int servicePid)
+        const sp<IBinder>& remoteCallback,
+        const String16& clientPackageName,
+        int cameraId, int cameraFacing,
+        int clientPid, uid_t clientUid,
+        int servicePid):
+        mClientPackageName(clientPackageName)
 {
     mCameraService = cameraService;
     mRemoteCallback = remoteCallback;
     mCameraId = cameraId;
     mCameraFacing = cameraFacing;
     mClientPid = clientPid;
+    mClientUid = clientUid;
     mServicePid = servicePid;
-
+    mOpsActive = false;
     mDestructionStarted = false;
 }
 
@@ -570,6 +603,66 @@
     mCameraService->removeClientByRemote(mRemoteCallback);
 }
 
+status_t CameraService::BasicClient::startCameraOps() {
+    int32_t res;
+
+    mOpsCallback = new OpsCallback(this);
+
+    mAppOpsManager.startWatchingMode(AppOpsManager::OP_CAMERA,
+            mClientPackageName, mOpsCallback);
+    res = mAppOpsManager.startOp(AppOpsManager::OP_CAMERA,
+            mClientUid, mClientPackageName);
+
+    if (res != AppOpsManager::MODE_ALLOWED) {
+        ALOGI("Camera %d: Access for \"%s\" has been revoked",
+                mCameraId, String8(mClientPackageName).string());
+        return PERMISSION_DENIED;
+    }
+    mOpsActive = true;
+    return OK;
+}
+
+status_t CameraService::BasicClient::finishCameraOps() {
+    if (mOpsActive) {
+        mAppOpsManager.finishOp(AppOpsManager::OP_CAMERA, mClientUid,
+                mClientPackageName);
+        mOpsActive = false;
+    }
+    mAppOpsManager.stopWatchingMode(mOpsCallback);
+    mOpsCallback.clear();
+
+    return OK;
+}
+
+void CameraService::BasicClient::opChanged(int32_t op, const String16& packageName) {
+    String8 name(packageName);
+    String8 myName(mClientPackageName);
+
+    if (op != AppOpsManager::OP_CAMERA) {
+        ALOGW("Unexpected app ops notification received: %d", op);
+        return;
+    }
+
+    int32_t res;
+    res = mAppOpsManager.checkOp(AppOpsManager::OP_CAMERA,
+            mClientUid, mClientPackageName);
+    ALOGV("checkOp returns: %d, %s ", res,
+            res == AppOpsManager::MODE_ALLOWED ? "ALLOWED" :
+            res == AppOpsManager::MODE_IGNORED ? "IGNORED" :
+            res == AppOpsManager::MODE_ERRORED ? "ERRORED" :
+            "UNKNOWN");
+
+    if (res != AppOpsManager::MODE_ALLOWED) {
+        ALOGI("Camera %d: Access for \"%s\" revoked", mCameraId,
+                myName.string());
+        // Reset the client PID to allow server-initiated disconnect,
+        // and to prevent further calls by client.
+        mClientPid = getCallingPid();
+        notifyError();
+        disconnect();
+    }
+}
+
 // ----------------------------------------------------------------------------
 
 Mutex* CameraService::Client::getClientLockFromCookie(void* user) {
@@ -592,25 +685,43 @@
     return client;
 }
 
+void CameraService::Client::notifyError() {
+    mCameraClient->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0);
+}
+
 // NOTE: function is idempotent
 void CameraService::Client::disconnect() {
     BasicClient::disconnect();
     mCameraService->setCameraFree(mCameraId);
 }
 
+CameraService::Client::OpsCallback::OpsCallback(wp<BasicClient> client):
+        mClient(client) {
+}
+
+void CameraService::Client::OpsCallback::opChanged(int32_t op,
+        const String16& packageName) {
+    sp<BasicClient> client = mClient.promote();
+    if (client != NULL) {
+        client->opChanged(op, packageName);
+    }
+}
+
 // ----------------------------------------------------------------------------
 //                  IProCamera
 // ----------------------------------------------------------------------------
 
 CameraService::ProClient::ProClient(const sp<CameraService>& cameraService,
-                const sp<IProCameraCallbacks>& remoteCallback,
-                int cameraId,
-                int cameraFacing,
-                int clientPid,
-                int servicePid)
- :       CameraService::BasicClient(cameraService, remoteCallback->asBinder(),
-                                   cameraId, cameraFacing,
-                                   clientPid, servicePid)
+        const sp<IProCameraCallbacks>& remoteCallback,
+        const String16& clientPackageName,
+        int cameraId,
+        int cameraFacing,
+        int clientPid,
+        uid_t clientUid,
+        int servicePid)
+        : CameraService::BasicClient(cameraService, remoteCallback->asBinder(),
+                clientPackageName, cameraId, cameraFacing,
+                clientPid,  clientUid, servicePid)
 {
     mRemoteCallback = remoteCallback;
 }
@@ -683,6 +794,10 @@
     return INVALID_OPERATION;
 }
 
+void CameraService::ProClient::notifyError() {
+    ALOGE("%s: not implemented yet", __FUNCTION__);
+}
+
 // ----------------------------------------------------------------------------
 
 static const int kDumpLockRetries = 50;
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 9e0f62a..b017505 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -19,7 +19,9 @@
 #define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
 
 #include <utils/Vector.h>
+#include <binder/AppOpsManager.h>
 #include <binder/BinderService.h>
+#include <binder/IAppOpsCallback.h>
 #include <camera/ICameraService.h>
 #include <hardware/camera.h>
 
@@ -54,9 +56,11 @@
     virtual int32_t     getNumberOfCameras();
     virtual status_t    getCameraInfo(int cameraId,
                                       struct CameraInfo* cameraInfo);
-    virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId);
-    virtual sp<IProCameraUser>
-                        connect(const sp<IProCameraCallbacks>& cameraCb, int cameraId);
+
+    virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId,
+            const String16& clientPackageName, int clientUid);
+    virtual sp<IProCameraUser> connect(const sp<IProCameraCallbacks>& cameraCb,
+            int cameraId);
 
     // Extra permissions checks
     virtual status_t    onTransact(uint32_t code, const Parcel& data,
@@ -100,9 +104,11 @@
     protected:
         BasicClient(const sp<CameraService>& cameraService,
                 const sp<IBinder>& remoteCallback,
+                const String16& clientPackageName,
                 int cameraId,
                 int cameraFacing,
                 int clientPid,
+                uid_t clientUid,
                 int servicePid);
 
         virtual ~BasicClient();
@@ -117,12 +123,41 @@
         sp<CameraService>               mCameraService;  // immutable after constructor
         int                             mCameraId;       // immutable after constructor
         int                             mCameraFacing;   // immutable after constructor
+        const String16                  mClientPackageName;
         pid_t                           mClientPid;
+        uid_t                           mClientUid;      // immutable after constructor
         pid_t                           mServicePid;     // immutable after constructor
 
         // - The app-side Binder interface to receive callbacks from us
         wp<IBinder>                     mRemoteCallback; // immutable after constructor
-    };
+
+        // permissions management
+        status_t                        startCameraOps();
+        status_t                        finishCameraOps();
+
+        // Notify client about a fatal error
+        virtual void                    notifyError() = 0;
+    private:
+        AppOpsManager                   mAppOpsManager;
+
+        class OpsCallback : public BnAppOpsCallback {
+        public:
+            OpsCallback(wp<BasicClient> client);
+            virtual void opChanged(int32_t op, const String16& packageName);
+
+        private:
+            wp<BasicClient> mClient;
+
+        }; // class OpsCallback
+
+        sp<OpsCallback> mOpsCallback;
+        // Track whether startCameraOps was called successfully, to avoid
+        // finishing what we didn't start.
+        bool            mOpsActive;
+
+        // IAppOpsCallback interface, indirected through opListener
+        virtual void opChanged(int32_t op, const String16& packageName);
+    }; // class BasicClient
 
     class Client : public BnCamera, public BasicClient
     {
@@ -153,9 +188,11 @@
         // Interface used by CameraService
         Client(const sp<CameraService>& cameraService,
                 const sp<ICameraClient>& cameraClient,
+                const String16& clientPackageName,
                 int cameraId,
                 int cameraFacing,
                 int clientPid,
+                uid_t clientUid,
                 int servicePid);
         ~Client();
 
@@ -169,19 +206,24 @@
         // convert client from cookie. Client lock should be acquired before getting Client.
         static Client*       getClientFromCookie(void* user);
 
+        virtual void         notifyError();
+
         // Initialized in constructor
 
         // - The app-side Binder interface to receive callbacks from us
         sp<ICameraClient>               mCameraClient;
-    };
+
+    }; // class Client
 
     class ProClient : public BnProCameraUser, public BasicClient {
     public:
         ProClient(const sp<CameraService>& cameraService,
                 const sp<IProCameraCallbacks>& remoteCallback,
+                const String16& clientPackageName,
                 int cameraId,
                 int cameraFacing,
                 int clientPid,
+                uid_t clientUid,
                 int servicePid);
 
         virtual ~ProClient();
@@ -217,9 +259,10 @@
         virtual status_t      cancelStream(int streamId);
 
     protected:
-        sp<IProCameraCallbacks> mRemoteCallback;
+        virtual void          notifyError();
 
-    };
+        sp<IProCameraCallbacks> mRemoteCallback;
+    }; // class ProClient
 
 private:
 
diff --git a/services/camera/libcameraservice/ProCamera2Client.cpp b/services/camera/libcameraservice/ProCamera2Client.cpp
index c264e2a..eda3012 100644
--- a/services/camera/libcameraservice/ProCamera2Client.cpp
+++ b/services/camera/libcameraservice/ProCamera2Client.cpp
@@ -43,12 +43,14 @@
 
 ProCamera2Client::ProCamera2Client(const sp<CameraService>& cameraService,
         const sp<IProCameraCallbacks>& remoteCallback,
+        const String16& clientPackageName,
         int cameraId,
         int cameraFacing,
         int clientPid,
+        uid_t clientUid,
         int servicePid):
-        ProClient(cameraService, remoteCallback,
-                cameraId, cameraFacing, clientPid, servicePid),
+        ProClient(cameraService, remoteCallback, clientPackageName,
+                cameraId, cameraFacing, clientPid, clientUid, servicePid),
         mSharedCameraCallbacks(remoteCallback)
 {
     ATRACE_CALL();
diff --git a/services/camera/libcameraservice/ProCamera2Client.h b/services/camera/libcameraservice/ProCamera2Client.h
index cd0a2ae..9f514f4 100644
--- a/services/camera/libcameraservice/ProCamera2Client.h
+++ b/services/camera/libcameraservice/ProCamera2Client.h
@@ -77,9 +77,11 @@
 
     ProCamera2Client(const sp<CameraService>& cameraService,
             const sp<IProCameraCallbacks>& remoteCallback,
+            const String16& clientPackageName,
             int cameraId,
             int cameraFacing,
             int clientPid,
+            uid_t clientUid,
             int servicePid);
     virtual ~ProCamera2Client();