summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRuben Brunk <rubenbrunk@google.com>2015-03-20 22:15:57 -0700
committerRuben Brunk <rubenbrunk@google.com>2015-03-31 12:11:10 -0700
commit36597b241c59eba7e55d5150092947a748c5e9cb (patch)
treebf174c4f6c45a2a5abfb3852effb567d5b653843
parentac41a6f253a69671f6e018fcc84daf0030615ca9 (diff)
downloadframeworks_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.cpp16
-rw-r--r--include/camera/ICameraService.h19
-rw-r--r--services/camera/libcameraservice/CameraService.cpp122
-rw-r--r--services/camera/libcameraservice/CameraService.h30
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) {