diff options
author | Ruben Brunk <rubenbrunk@google.com> | 2015-03-20 22:15:57 -0700 |
---|---|---|
committer | Ruben Brunk <rubenbrunk@google.com> | 2015-03-31 12:11:10 -0700 |
commit | 36597b241c59eba7e55d5150092947a748c5e9cb (patch) | |
tree | bf174c4f6c45a2a5abfb3852effb567d5b653843 | |
parent | ac41a6f253a69671f6e018fcc84daf0030615ca9 (diff) | |
download | frameworks_av-36597b241c59eba7e55d5150092947a748c5e9cb.zip frameworks_av-36597b241c59eba7e55d5150092947a748c5e9cb.tar.gz frameworks_av-36597b241c59eba7e55d5150092947a748c5e9cb.tar.bz2 |
camera2: Enforce client eviction on user switch.
Bug: 19186859
Change-Id: I172a2ce46c8e8a131ae7e8dd99d60c5f4f0d6668
-rw-r--r-- | camera/ICameraService.cpp | 16 | ||||
-rw-r--r-- | include/camera/ICameraService.h | 19 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraService.cpp | 122 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraService.h | 30 |
4 files changed, 168 insertions, 19 deletions
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp index 63c82cc..51a775b 100644 --- a/camera/ICameraService.cpp +++ b/camera/ICameraService.cpp @@ -302,6 +302,15 @@ public: status_t res = data.readInt32(); return res; } + + virtual void notifySystemEvent(int eventId, int arg0) { + Parcel data, reply; + data.writeInt32(eventId); + data.writeInt32(arg0); + remote()->transact(BnCameraService::NOTIFY_SYSTEM_EVENT, data, &reply, + IBinder::FLAG_ONEWAY); + } + }; IMPLEMENT_META_INTERFACE(CameraService, "android.hardware.ICameraService"); @@ -470,6 +479,13 @@ status_t BnCameraService::onTransact( reply->writeInt32(status); return NO_ERROR; } break; + case NOTIFY_SYSTEM_EVENT: { + CHECK_INTERFACE(ICameraService, data, reply); + int eventId = data.readInt32(); + int arg0 = data.readInt32(); + notifySystemEvent(eventId, arg0); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h index c8d3d19..cad275e 100644 --- a/include/camera/ICameraService.h +++ b/include/camera/ICameraService.h @@ -51,6 +51,7 @@ public: SUPPORTS_CAMERA_API, CONNECT_LEGACY, SET_TORCH_MODE, + NOTIFY_SYSTEM_EVENT, }; enum { @@ -64,7 +65,18 @@ public: enum { CAMERA_HAL_API_VERSION_UNSPECIFIED = -1 - }; + }; + + /** + * Keep up-to-date with declarations in + * frameworks/base/services/core/java/com/android/server/camera/CameraService.java + * + * These event codes are intended to be used with the notifySystemEvent call. + */ + enum { + NO_EVENT = 0, + USER_SWITCHED, + }; public: DECLARE_META_INTERFACE(CameraService); @@ -148,6 +160,11 @@ public: */ virtual status_t setTorchMode(const String16& cameraId, bool enabled, const sp<IBinder>& clientBinder) = 0; + + /** + * Notify the camera service of a system event. Should only be called from system_server. + */ + virtual void notifySystemEvent(int eventId, int arg0) = 0; }; // ---------------------------------------------------------------------------- diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index c2df489..e9c96c6 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -35,7 +35,6 @@ #include <binder/ProcessInfoService.h> #include <cutils/atomic.h> #include <cutils/properties.h> -#include <cutils/multiuser.h> #include <gui/Surface.h> #include <hardware/hardware.h> #include <media/AudioSystem.h> @@ -123,9 +122,8 @@ static void torch_mode_status_change( // should be ok for now. static CameraService *gCameraService; -CameraService::CameraService() - : mEventLog(DEFAULT_EVICTION_LOG_LENGTH), mSoundRef(0), mModule(0), mFlashlight(0) -{ +CameraService::CameraService() : mEventLog(DEFAULT_EVICTION_LOG_LENGTH), + mLastUserId(DEFAULT_LAST_USER_ID), mSoundRef(0), mModule(0), mFlashlight(0) { ALOGI("CameraService started (pid=%d)", getpid()); gCameraService = this; @@ -757,7 +755,8 @@ status_t CameraService::getLegacyParametersLazy(int cameraId, return INVALID_OPERATION; } -status_t CameraService::validateConnect(const String8& cameraId, /*inout*/int& clientUid) const { +status_t CameraService::validateConnectLocked(const String8& cameraId, /*inout*/int& clientUid) + const { int callingPid = getCallingPid(); @@ -797,6 +796,13 @@ status_t CameraService::validateConnect(const String8& cameraId, /*inout*/int& c return -EACCES; } + // Only allow clients who are being used by the current foreground device user. + if (mLastUserId != clientUserId && mLastUserId != DEFAULT_LAST_USER_ID) { + ALOGE("CameraService::connect X (PID %d) rejected (cannot connect from non-foreground " + "device user)", callingPid); + return PERMISSION_DENIED; + } + return checkIfDeviceIsUsable(cameraId); } @@ -1163,6 +1169,21 @@ status_t CameraService::setTorchMode(const String16& cameraId, bool enabled, return OK; } +void CameraService::notifySystemEvent(int eventId, int arg0) { + switch(eventId) { + case ICameraService::USER_SWITCHED: { + doUserSwitch(/*newUserId*/arg0); + break; + } + case ICameraService::NO_EVENT: + default: { + ALOGW("%s: Received invalid system event from system_server: %d", __FUNCTION__, + eventId); + break; + } + } +} + status_t CameraService::addListener( const sp<ICameraServiceListener>& listener) { ALOGV("%s: Add listener %p", __FUNCTION__, listener.get()); @@ -1351,6 +1372,8 @@ bool CameraService::evictClientIdByRemote(const wp<IBinder>& remote) { // other clients from connecting in mServiceLockWrapper if held mServiceLock.unlock(); + // Do not clear caller identity, remote caller should be client proccess + for (auto& i : evicted) { if (i.get() != nullptr) { i->disconnect(); @@ -1392,6 +1415,60 @@ sp<CameraService::BasicClient> CameraService::removeClientLocked(const String8& return clientDescriptorPtr->getValue(); } +void CameraService::doUserSwitch(int newUserId) { + // Acquire mServiceLock and prevent other clients from connecting + std::unique_ptr<AutoConditionLock> lock = + AutoConditionLock::waitAndAcquire(mServiceLockWrapper); + + if (newUserId <= 0) { + ALOGW("%s: Bad user ID %d given during user switch, resetting to default.", __FUNCTION__, + newUserId); + newUserId = DEFAULT_LAST_USER_ID; + } + + mLastUserId = newUserId; + + // Current user has switched, evict all current clients. + std::vector<sp<BasicClient>> evicted; + for (auto& i : mActiveClientManager.getAll()) { + auto clientSp = i->getValue(); + + if (clientSp.get() == nullptr) { + ALOGE("%s: Dead client still in mActiveClientManager.", __FUNCTION__); + continue; + } + + evicted.push_back(clientSp); + + String8 curTime = getFormattedCurrentTime(); + + ALOGE("Evicting conflicting client for camera ID %s due to user change", + i->getKey().string()); + // Log the clients evicted + mEventLog.add(String8::format("%s : EVICT device %s client for package %s (PID %" + PRId32 ", priority %" PRId32 ")\n - Evicted due to user switch.", + curTime.string(), i->getKey().string(), + String8{clientSp->getPackageName()}.string(), i->getOwnerId(), + i->getPriority())); + + } + + // Do not hold mServiceLock while disconnecting clients, but retain the condition + // blocking other clients from connecting in mServiceLockWrapper if held. + mServiceLock.unlock(); + + // Clear caller identity temporarily so client disconnect PID checks work correctly + int64_t token = IPCThreadState::self()->clearCallingIdentity(); + + for (auto& i : evicted) { + i->disconnect(); + } + + IPCThreadState::self()->restoreCallingIdentity(token); + + // Reacquire mServiceLock + mServiceLock.lock(); +} void CameraService::logDisconnected(const String8& cameraId, int clientPid, const String8& clientPackage) { @@ -1411,16 +1488,18 @@ void CameraService::logConnected(const String8& cameraId, int clientPid, curTime.string(), cameraId.string(), clientPackage.string(), clientPid)); } -status_t CameraService::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { +status_t CameraService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags) { + + const int pid = getCallingPid(); + const int selfPid = getpid(); + // Permission checks switch (code) { case BnCameraService::CONNECT: case BnCameraService::CONNECT_DEVICE: - case BnCameraService::CONNECT_LEGACY: - const int pid = getCallingPid(); - const int self_pid = getpid(); - if (pid != self_pid) { + case BnCameraService::CONNECT_LEGACY: { + if (pid != selfPid) { // we're called from a different process, do the real check if (!checkCallingPermission( String16("android.permission.CAMERA"))) { @@ -1431,6 +1510,21 @@ status_t CameraService::onTransact( } } break; + } + case BnCameraService::NOTIFY_SYSTEM_EVENT: { + if (pid != selfPid) { + // Ensure we're being called by system_server, or similar process with + // permissions to notify the camera service about system events + if (!checkCallingPermission( + String16("android.permission.CAMERA_SEND_SYSTEM_EVENTS"))) { + const int uid = getCallingUid(); + ALOGE("Permission Denial: cannot send updates to camera service about system" + " events from pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + } + break; + } } return BnCameraService::onTransact(code, data, reply, flags); @@ -1544,7 +1638,11 @@ CameraService::BasicClient::~BasicClient() { } void CameraService::BasicClient::disconnect() { - if (mDisconnected) return; + if (mDisconnected) { + ALOGE("%s: Disconnect called on already disconnected client for device %d", __FUNCTION__, + mCameraId); + return; + } mDisconnected = true;; mCameraService->removeByClient(this); diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 53f1c72..ca1c504 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -17,6 +17,7 @@ #ifndef ANDROID_SERVERS_CAMERA_CAMERASERVICE_H #define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H +#include <cutils/multiuser.h> #include <utils/Vector.h> #include <utils/KeyedVector.h> #include <binder/AppOpsManager.h> @@ -92,6 +93,11 @@ public: // Default number of messages to store in eviction log static const size_t DEFAULT_EVICTION_LOG_LENGTH = 50; + enum { + // Default last user id + DEFAULT_LAST_USER_ID = 0, + }; + // Implementation of BinderService<T> static char const* getServiceName() { return "media.camera"; } @@ -145,6 +151,8 @@ public: virtual status_t setTorchMode(const String16& cameraId, bool enabled, const sp<IBinder>& clientBinder); + virtual void notifySystemEvent(int eventId, int arg0); + // OK = supports api of that version, -EOPNOTSUPP = does not support virtual status_t supportsCameraApi( int cameraId, int apiVersion); @@ -447,7 +455,7 @@ private: virtual void onFirstRef(); // Check if we can connect, before we acquire the service lock. - status_t validateConnect(const String8& cameraId, /*inout*/int& clientUid) const; + status_t validateConnectLocked(const String8& cameraId, /*inout*/int& clientUid) const; // Handle active client evictions, and update service state. // Only call with with mServiceLock held. @@ -485,6 +493,9 @@ private: // Circular buffer for storing event logging for dumps RingBuffer<String8> mEventLog; + // UID of last user. + int mLastUserId; + /** * Get the camera state for a given camera id. * @@ -530,6 +541,11 @@ private: sp<CameraService::BasicClient> removeClientLocked(const String8& cameraId); /** + * Handle a notification that the current device user has changed. + */ + void doUserSwitch(int newUserId); + + /** * Add a event log message that a client has been disconnected. */ void logDisconnected(const String8& cameraId, int clientPid, const String8& clientPackage); @@ -702,22 +718,24 @@ status_t CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String "Camera API version %d", clientPid, clientName8.string(), cameraId.string(), halVersion, static_cast<int>(effectiveApiLevel)); - // Enforce client permissions and do basic sanity checks - if((ret = validateConnect(cameraId, /*inout*/clientUid)) != NO_ERROR) { - return ret; - } - sp<CLIENT> client = nullptr; { // Acquire mServiceLock and prevent other clients from connecting std::unique_ptr<AutoConditionLock> lock = AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS); + if (lock == nullptr) { ALOGE("CameraService::connect X (PID %d) rejected (too many other clients connecting)." , clientPid); return -EBUSY; } + // Enforce client permissions and do basic sanity checks + if((ret = validateConnectLocked(cameraId, /*inout*/clientUid)) != NO_ERROR) { + return ret; + } + mLastUserId = multiuser_get_user_id(clientUid); + // Check the shim parameters after acquiring lock, if they have already been updated and // we were doing a shim update, return immediately if (shimUpdateOnly) { |