Camera: Update listeners about permission changes

Camera service listeners must be able to receive
information about camera access permission changes.

Bug: 121379978
Test: Camera CTS
Change-Id: I2e13fdd35a267901a3caa0e0ce78ab1cea83e7ab
gugelfrei
Emilian Peev 5 years ago
parent 3f1962974d
commit 53722fa75c

@ -108,7 +108,7 @@ interface ICameraService
* *
* Also returns the set of currently-known camera IDs and state of each device. * Also returns the set of currently-known camera IDs and state of each device.
* Adding a listener will trigger the torch status listener to fire for all * Adding a listener will trigger the torch status listener to fire for all
* devices that have a flash unit * devices that have a flash unit.
*/ */
CameraStatus[] addListener(ICameraServiceListener listener); CameraStatus[] addListener(ICameraServiceListener listener);

@ -76,4 +76,11 @@ interface ICameraServiceListener
const int TORCH_STATUS_UNKNOWN = -1; const int TORCH_STATUS_UNKNOWN = -1;
oneway void onTorchStatusChanged(int status, String cameraId); oneway void onTorchStatusChanged(int status, String cameraId);
/**
* Notify registered clients about camera access priority changes.
* Clients which were previously unable to open a certain camera device
* can retry after receiving this callback.
*/
oneway void onCameraAccessPrioritiesChanged();
} }

@ -86,6 +86,11 @@ class CameraManagerGlobal final : public RefBase {
return binder::Status::ok(); return binder::Status::ok();
} }
// Access priority API not implemented yet
virtual binder::Status onCameraAccessPrioritiesChanged() {
return binder::Status::ok();
}
private: private:
const wp<CameraManagerGlobal> mCameraManager; const wp<CameraManagerGlobal> mCameraManager;
}; };

@ -90,6 +90,11 @@ public:
return binder::Status::ok(); return binder::Status::ok();
}; };
virtual binder::Status onCameraAccessPrioritiesChanged() {
// No op
return binder::Status::ok();
}
bool waitForNumCameras(size_t num) const { bool waitForNumCameras(size_t num) const {
Mutex::Autolock l(mLock); Mutex::Autolock l(mLock);

@ -227,7 +227,7 @@ void CameraService::broadcastTorchModeStatus(const String8& cameraId, TorchModeS
Mutex::Autolock lock(mStatusListenerLock); Mutex::Autolock lock(mStatusListenerLock);
for (auto& i : mListenerList) { for (auto& i : mListenerList) {
i.second->onTorchStatusChanged(mapToInterface(status), String16{cameraId}); i.second->getListener()->onTorchStatusChanged(mapToInterface(status), String16{cameraId});
} }
} }
@ -1654,6 +1654,18 @@ Status CameraService::notifySystemEvent(int32_t eventId,
return Status::ok(); return Status::ok();
} }
void CameraService::notifyMonitoredUids() {
Mutex::Autolock lock(mStatusListenerLock);
for (const auto& it : mListenerList) {
auto ret = it.second->getListener()->onCameraAccessPrioritiesChanged();
if (!ret.isOk()) {
ALOGE("%s: Failed to trigger permission callback: %d", __FUNCTION__,
ret.exceptionCode());
}
}
}
Status CameraService::notifyDeviceStateChange(int64_t newState) { Status CameraService::notifyDeviceStateChange(int64_t newState) {
const int pid = CameraThreadState::getCallingPid(); const int pid = CameraThreadState::getCallingPid();
const int selfPid = getpid(); const int selfPid = getpid();
@ -1721,15 +1733,25 @@ Status CameraService::addListenerHelper(const sp<ICameraServiceListener>& listen
{ {
Mutex::Autolock lock(mStatusListenerLock); Mutex::Autolock lock(mStatusListenerLock);
for (auto& it : mListenerList) { for (const auto &it : mListenerList) {
if (IInterface::asBinder(it.second) == IInterface::asBinder(listener)) { if (IInterface::asBinder(it.second->getListener()) == IInterface::asBinder(listener)) {
ALOGW("%s: Tried to add listener %p which was already subscribed", ALOGW("%s: Tried to add listener %p which was already subscribed",
__FUNCTION__, listener.get()); __FUNCTION__, listener.get());
return STATUS_ERROR(ERROR_ALREADY_EXISTS, "Listener already registered"); return STATUS_ERROR(ERROR_ALREADY_EXISTS, "Listener already registered");
} }
} }
mListenerList.emplace_back(isVendorListener, listener); auto clientUid = CameraThreadState::getCallingUid();
sp<ServiceListener> serviceListener = new ServiceListener(this, listener, clientUid);
auto ret = serviceListener->initialize();
if (ret != NO_ERROR) {
String8 msg = String8::format("Failed to initialize service listener: %s (%d)",
strerror(-ret), ret);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.string());
}
mListenerList.emplace_back(isVendorListener, serviceListener);
mUidPolicy->registerMonitorUid(clientUid);
} }
/* Collect current devices and status */ /* Collect current devices and status */
@ -1776,7 +1798,9 @@ Status CameraService::removeListener(const sp<ICameraServiceListener>& listener)
{ {
Mutex::Autolock lock(mStatusListenerLock); Mutex::Autolock lock(mStatusListenerLock);
for (auto it = mListenerList.begin(); it != mListenerList.end(); it++) { for (auto it = mListenerList.begin(); it != mListenerList.end(); it++) {
if (IInterface::asBinder(it->second) == IInterface::asBinder(listener)) { if (IInterface::asBinder(it->second->getListener()) == IInterface::asBinder(listener)) {
mUidPolicy->unregisterMonitorUid(it->second->getListenerUid());
IInterface::asBinder(listener)->unlinkToDeath(it->second);
mListenerList.erase(it); mListenerList.erase(it);
return Status::ok(); return Status::ok();
} }
@ -2396,6 +2420,8 @@ status_t CameraService::BasicClient::startCameraOps() {
sCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_OPEN, sCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_OPEN,
mCameraIdStr, mCameraFacing, mClientPackageName, apiLevel); mCameraIdStr, mCameraFacing, mClientPackageName, apiLevel);
sCameraService->mUidPolicy->registerMonitorUid(mClientUid);
return OK; return OK;
} }
@ -2433,6 +2459,8 @@ status_t CameraService::BasicClient::finishCameraOps() {
} }
mOpsCallback.clear(); mOpsCallback.clear();
sCameraService->mUidPolicy->unregisterMonitorUid(mClientUid);
return OK; return OK;
} }
@ -2523,7 +2551,7 @@ void CameraService::UidPolicy::registerSelf() {
if (mRegistered) return; if (mRegistered) return;
am.registerUidObserver(this, ActivityManager::UID_OBSERVER_GONE am.registerUidObserver(this, ActivityManager::UID_OBSERVER_GONE
| ActivityManager::UID_OBSERVER_IDLE | ActivityManager::UID_OBSERVER_IDLE
| ActivityManager::UID_OBSERVER_ACTIVE, | ActivityManager::UID_OBSERVER_ACTIVE | ActivityManager::UID_OBSERVER_PROCSTATE,
ActivityManager::PROCESS_STATE_UNKNOWN, ActivityManager::PROCESS_STATE_UNKNOWN,
String16("cameraserver")); String16("cameraserver"));
status_t res = am.linkToDeath(this); status_t res = am.linkToDeath(this);
@ -2569,6 +2597,51 @@ void CameraService::UidPolicy::onUidIdle(uid_t uid, bool /* disabled */) {
} }
} }
void CameraService::UidPolicy::onUidStateChanged(uid_t uid, int32_t procState,
int64_t /*procStateSeq*/) {
bool procStateChange = false;
{
Mutex::Autolock _l(mUidLock);
if ((mMonitoredUids.find(uid) != mMonitoredUids.end()) &&
(mMonitoredUids[uid].first != procState)) {
mMonitoredUids[uid].first = procState;
procStateChange = true;
}
}
if (procStateChange) {
sp<CameraService> service = mService.promote();
if (service != nullptr) {
service->notifyMonitoredUids();
}
}
}
void CameraService::UidPolicy::registerMonitorUid(uid_t uid) {
Mutex::Autolock _l(mUidLock);
auto it = mMonitoredUids.find(uid);
if (it != mMonitoredUids.end()) {
it->second.second++;
} else {
mMonitoredUids.emplace(
std::pair<uid_t, std::pair<int32_t, size_t>> (uid,
std::pair<int32_t, size_t> (ActivityManager::PROCESS_STATE_NONEXISTENT, 1)));
}
}
void CameraService::UidPolicy::unregisterMonitorUid(uid_t uid) {
Mutex::Autolock _l(mUidLock);
auto it = mMonitoredUids.find(uid);
if (it != mMonitoredUids.end()) {
it->second.second--;
if (it->second.second == 0) {
mMonitoredUids.erase(it);
}
} else {
ALOGE("%s: Trying to unregister uid: %d which is not monitored!", __FUNCTION__, uid);
}
}
bool CameraService::UidPolicy::isUidActive(uid_t uid, String16 callingPackage) { bool CameraService::UidPolicy::isUidActive(uid_t uid, String16 callingPackage) {
Mutex::Autolock _l(mUidLock); Mutex::Autolock _l(mUidLock);
return isUidActiveLocked(uid, callingPackage); return isUidActiveLocked(uid, callingPackage);
@ -3118,7 +3191,8 @@ void CameraService::updateStatus(StatusInternal status, const String8& cameraId,
cameraId.c_str()); cameraId.c_str());
continue; continue;
} }
listener.second->onStatusChanged(mapToInterface(status), String16(cameraId)); listener.second->getListener()->onStatusChanged(mapToInterface(status),
String16(cameraId));
} }
}); });
} }

@ -179,6 +179,9 @@ public:
/*out*/ /*out*/
std::vector<hardware::CameraStatus>* cameraStatuses, bool isVendor = false); std::vector<hardware::CameraStatus>* cameraStatuses, bool isVendor = false);
// Monitored UIDs availability notification
void notifyMonitoredUids();
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// Client functionality // Client functionality
@ -543,11 +546,14 @@ private:
void onUidGone(uid_t uid, bool disabled); void onUidGone(uid_t uid, bool disabled);
void onUidActive(uid_t uid); void onUidActive(uid_t uid);
void onUidIdle(uid_t uid, bool disabled); void onUidIdle(uid_t uid, bool disabled);
void onUidStateChanged(uid_t uid __unused, int32_t procState __unused, int64_t procStateSeq __unused) {} void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq);
void addOverrideUid(uid_t uid, String16 callingPackage, bool active); void addOverrideUid(uid_t uid, String16 callingPackage, bool active);
void removeOverrideUid(uid_t uid, String16 callingPackage); void removeOverrideUid(uid_t uid, String16 callingPackage);
void registerMonitorUid(uid_t uid);
void unregisterMonitorUid(uid_t uid);
// IBinder::DeathRecipient implementation // IBinder::DeathRecipient implementation
virtual void binderDied(const wp<IBinder> &who); virtual void binderDied(const wp<IBinder> &who);
private: private:
@ -558,6 +564,8 @@ private:
bool mRegistered; bool mRegistered;
wp<CameraService> mService; wp<CameraService> mService;
std::unordered_set<uid_t> mActiveUids; std::unordered_set<uid_t> mActiveUids;
// Monitored uid map to cached procState and refCount pair
std::unordered_map<uid_t, std::pair<int32_t, size_t>> mMonitoredUids;
std::unordered_map<uid_t, bool> mOverrideUids; std::unordered_map<uid_t, bool> mOverrideUids;
}; // class UidPolicy }; // class UidPolicy
@ -790,8 +798,33 @@ private:
sp<CameraProviderManager> mCameraProviderManager; sp<CameraProviderManager> mCameraProviderManager;
class ServiceListener : public virtual IBinder::DeathRecipient {
public:
ServiceListener(sp<CameraService> parent, sp<hardware::ICameraServiceListener> listener,
int uid) : mParent(parent), mListener(listener), mListenerUid(uid) {}
status_t initialize() {
return IInterface::asBinder(mListener)->linkToDeath(this);
}
virtual void binderDied(const wp<IBinder> &/*who*/) {
auto parent = mParent.promote();
if (parent.get() != nullptr) {
parent->removeListener(mListener);
}
}
int getListenerUid() { return mListenerUid; }
sp<hardware::ICameraServiceListener> getListener() { return mListener; }
private:
wp<CameraService> mParent;
sp<hardware::ICameraServiceListener> mListener;
int mListenerUid;
};
// Guarded by mStatusListenerMutex // Guarded by mStatusListenerMutex
std::vector<std::pair<bool, sp<hardware::ICameraServiceListener>>> mListenerList; std::vector<std::pair<bool, sp<ServiceListener>>> mListenerList;
Mutex mStatusListenerLock; Mutex mStatusListenerLock;

@ -50,6 +50,10 @@ struct H2BCameraServiceListener :
virtual ::android::binder::Status onTorchStatusChanged( virtual ::android::binder::Status onTorchStatusChanged(
int32_t status, const ::android::String16& cameraId) override; int32_t status, const ::android::String16& cameraId) override;
virtual binder::Status onCameraAccessPrioritiesChanged() {
// TODO: no implementation yet.
return binder::Status::ok();
}
}; };
} // implementation } // implementation

Loading…
Cancel
Save