case ASKUSER_API_CONNECTION_ERROR:
ret = PRIVACY_PRIVILEGE_MANAGER_ERROR_IO_ERROR;
break;
+ case ASKUSER_API_ALREADY_IN_PROGRESS:
+ ret = PRIVACY_PRIVILEGE_MANAGER_ERROR_ALREADY_IN_PROGRESS;
default:
break;
}
}
static void ppm_popup_response_callback(UNUSED int request_id, askuser_call_cause cause,
- askuser_popup_result result, void *p_user_data)
+ askuser_popup_result result, const char *privilege,
+ void *p_user_data)
{
ppm_callback_closure *callback_closure = (ppm_callback_closure *) p_user_data;
ppm_call_cause_e ppm_cause = askuser_client_popup_cause_to_ppm(cause);
ppm_check_result_e ppm_result = askuser_client_popup_result_to_ppm(result);
- callback_closure->callback(ppm_cause, ppm_result, callback_closure->user_data);
+ callback_closure->callback(ppm_cause, ppm_result, privilege, callback_closure->user_data);
free(callback_closure);
}
PRIVACY_PRIVILEGE_MANAGER_ERROR_IO_ERROR = TIZEN_ERROR_IO_ERROR,
/**< Invalid parameter */
PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER,
+ /**< Operation already in progress */
+ PRIVACY_PRIVILEGE_MANAGER_ERROR_ALREADY_IN_PROGRESS = TIZEN_ERROR_ALREADY_IN_PROGRESS,
/**< Out of memory */
PRIVACY_PRIVILEGE_MANAGER_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY,
/**< Unknown error */
* @param[in] result A result of a response triggered by calling ppm_popup_request().
* This is a valid value only if the @a cause parameter is equal to
* **PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ANSWER**.
- * @param[in] user_data User specific data, this parameter is passed
+ * @param[in] privilege A privilege that has been checked.
+ * @param[in] user_data User specific data, this parameter has been passed
* to ppm_popup_request().
*
* @see ppm_popup_request()
*/
typedef void (*ppm_popup_response_cb) (ppm_call_cause_e cause,
ppm_popup_result_e result,
+ const char *privilege,
void *user_data);
/**
* the registered callback.
*
* @return 0 on success, otherwise a negative error value
- * @retval #PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE Successful
- * @retval #PRIVACY_PRIVILEGE_MANAGER_ERROR_IO_ERROR I/O error
- * @retval #PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #PRIVACY_PRIVILEGE_MANAGER_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #PRIVACY_PRIVILEGE_MANAGER_ERROR_UNKNOWN Unknown error
+ * @retval #PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE Successful
+ * @retval #PRIVACY_PRIVILEGE_MANAGER_ERROR_IO_ERROR I/O error
+ * @retval #PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #PRIVACY_PRIVILEGE_MANAGER_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #PRIVACY_PRIVILEGE_MANAGER_ERROR_ALREADY_IN_PROGRESS Operation already in progress
+ * @retval #PRIVACY_PRIVILEGE_MANAGER_ERROR_UNKNOWN Unknown error
*
* @post ppm_popup_response_cb() will be invoked.
* @see ppm_popup_response_cb()
struct ClientRequest {
RequestId m_id;
- Privilege m_privilege;
GMainLoop *m_mainLoop;
bool m_stopAppAfterDeny;
};
case PRIVACY_PRIVILEGE_MANAGER_ERROR_UNKNOWN:
printf("Unknown error\n");
break;
+ case PRIVACY_PRIVILEGE_MANAGER_ERROR_ALREADY_IN_PROGRESS:
+ printf("Operation already in progress\n");
+ break;
}
}
private:
- static void popupResponseCallback(ppm_call_cause_e cause, ppm_popup_result_e result, void *user_data) {
+ static void popupResponseCallback(ppm_call_cause_e cause, ppm_popup_result_e result,
+ const char *privilege, void *user_data) {
ClientRequest *request = static_cast<ClientRequest *>(user_data);
if (request == nullptr) {
printf("ERROR: User data is nullptr\n");
return;
}
- printf("localId: %d privilege: \"%s\" ", request->m_id, request->m_privilege.c_str());
+ printf("localId: %d privilege: \"%s\" ", request->m_id, privilege);
switch (cause) {
case PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ANSWER:
printf("sending localId: %d privilege: \"%s\"\n", clientRequestId, privilege);
- request = new ClientRequest{ clientRequestId++, privilege, m_mainloop, stopAppAfterDeny };
+ request = new ClientRequest{ clientRequestId++, m_mainloop, stopAppAfterDeny };
err = static_cast<ppm_error_e>(ppm_popup_request(privilege, &AppContext::popupResponseCallback, request));
if (err != PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE) {
delete request;
virtual askuser_check_result checkPrivilege(const std::string &privilege) = 0;
virtual RequestId popupRequest(const PopupCallbackClosure &closure,
const std::string &privilege) = 0;
+ virtual bool popupRequestInProgress(const std::string &privilege) const = 0;
};
} // namespace Client
}
return AskUser::Client::tryCatch([&]() {
- AskUser::Client::PopupCallbackClosure closure(response_callback, p_user_data);
+ if (p_client->impl->popupRequestInProgress(privilege)) {
+ return ASKUSER_API_ALREADY_IN_PROGRESS;
+ }
+
+ AskUser::Client::PopupCallbackClosure closure(response_callback, privilege, p_user_data);
AskUser::Client::RequestId id = p_client->impl->popupRequest(closure, privilege);
if (p_request_id) {
namespace {
-int eventsToAskUserMask(int events)
+inline int eventsToAskUserMask(int events)
{
return ((events & ASKUSER_READ_EVENT) ? AskUser::Protocol::FdMask::READ : 0) |
((events & ASKUSER_WRITE_EVENT) ? AskUser::Protocol::FdMask::WRITE : 0);
}
-int askUserMaskToEvents(int mask)
+inline int askUserMaskToEvents(int mask)
{
return ((AskUser::Protocol::FdMask::READ & mask) ? ASKUSER_READ_EVENT : 0) |
((AskUser::Protocol::FdMask::WRITE & mask) ? ASKUSER_WRITE_EVENT : 0);
}
-askuser_popup_result responseToAskUserPopupResult(int response)
+inline askuser_popup_result responseToAskUserPopupResult(int response)
{
switch (response) {
case ASKUSER_ALLOW_FOREVER:
return ASKUSER_POPUP_RESULT_DENY_ONCE;
}
+inline askuser_call_cause deduceCauseFromResponse(int response)
+{
+ if (response == ASKUSER_UNKNOWN_ERROR) {
+ return ASKUSER_CALL_CAUSE_ERROR;
+ }
+
+ return ASKUSER_CALL_CAUSE_ANSWER;
+}
+
} // namespace
namespace AskUser {
ApiInterfaceImpl::~ApiInterfaceImpl()
{
- for (const auto &closure : m_callbacks) {
- closure.second(closure.first, askuser_call_cause::ASKUSER_CALL_CAUSE_FINALIZE,
- askuser_popup_result::ASKUSER_POPUP_RESULT_DENY_ONCE);
- }
+ respondToAllRequests(ASKUSER_CALL_CAUSE_FINALIZE, ASKUSER_POPUP_RESULT_DENY_ONCE);
- m_callbacks.clear();
m_channel.reset();
}
auto policies = fetch.fetchPolicy();
if (policies.size() != 1) {
- ALOGE("Unusual situation, there are " << policies.size() << " policies for (" << appId << ", " << geteuid() << ", " << privilege << ")");
+ ALOGE("Unusual situation, there are " << policies.size() <<
+ " policies for (" << appId << ", " << geteuid() << ", " << privilege << ")");
return ASKUSER_CHECK_RESULT_DENY;
}
RequestId ApiInterfaceImpl::popupRequest(const PopupCallbackClosure &closure,
const std::string &privilege)
{
- Client::RequestId id = static_cast<Client::RequestId>(m_channel->popupRequest(privilege));
+ RequestId id = static_cast<RequestId>(m_channel->popupRequest(privilege));
+
+ auto it = m_popupClosures.find(id);
+ if (it != m_popupClosures.end()) {
+ ALOGE("Popup closure exists for id: " << id <<
+ " privilege: " << it->second.privilege() << ", replacing");
+ popupResponse(id, ASKUSER_UNKNOWN_ERROR);
+ }
- auto it = m_callbacks.find(id);
- if (it != m_callbacks.end()) {
- it->second(it->first, ASKUSER_CALL_CAUSE_ERROR, ASKUSER_POPUP_RESULT_DENY_ONCE);
- m_callbacks.erase(it);
+ if (popupRequestInProgress(privilege)) {
+ ALOGE("Privilege " << closure.privilege() << " already exists in the pending privileges set");
}
- m_callbacks.insert({id, closure});
+ m_requestedPrivileges.insert(privilege);
+ m_popupClosures.insert({id, closure});
return id;
}
+bool ApiInterfaceImpl::popupRequestInProgress(const std::string &privilege) const
+{
+ return m_requestedPrivileges.find(privilege) != m_requestedPrivileges.end();
+}
+
void ApiInterfaceImpl::updateConnection(Protocol::ConnectionFd fd, int mask)
{
m_statusClosure(fd, askUserMaskToEvents(mask));
- // remove all pending events
+ // the connection is about to close, respond to all pending requests
if (mask == ASKUSER_EMPTY_EVENTS) {
- for (const auto &closure : m_callbacks) {
- closure.second(closure.first, ASKUSER_CALL_CAUSE_ERROR, ASKUSER_POPUP_RESULT_DENY_ONCE);
- }
-
- m_callbacks.clear();
+ respondToAllRequests(ASKUSER_CALL_CAUSE_ERROR, ASKUSER_POPUP_RESULT_DENY_ONCE);
}
}
void ApiInterfaceImpl::popupResponse(Protocol::RequestId id, int response)
{
- auto it = m_callbacks.find(id);
- if (it == m_callbacks.end()) {
+ auto it = m_popupClosures.find(id);
+ if (it == m_popupClosures.end()) {
+ ALOGE("Couldn't find popup callback closure for id: " << id);
return;
}
- askuser_call_cause cause = ASKUSER_CALL_CAUSE_ANSWER;
- if (response == ASKUSER_UNKNOWN_ERROR) {
- cause = ASKUSER_CALL_CAUSE_ERROR;
+ const auto &closure = it->second;
+ if (!popupRequestInProgress(closure.privilege())) {
+ ALOGE("Couldn't find privilege " << closure.privilege() << " in the pending privileges set");
}
+ askuser_call_cause cause = deduceCauseFromResponse(response);
askuser_popup_result res = responseToAskUserPopupResult(response);
- it->second(id, cause, res);
- m_callbacks.erase(it);
+
+ closure(id, cause, res);
+
+ m_requestedPrivileges.erase(closure.privilege());
+ m_popupClosures.erase(it);
+}
+
+void ApiInterfaceImpl::respondToAllRequests(askuser_call_cause cause, askuser_popup_result result)
+{
+ for (const auto &closure : m_popupClosures) {
+ closure.second(closure.first, cause, result);
+ }
+
+ m_requestedPrivileges.clear();
+ m_popupClosures.clear();
}
} // namespace Client
#pragma once
+#include <map>
#include <memory>
+#include <set>
#include <ApiInterface.h>
#include <PopupCallbackClosure.h>
virtual askuser_check_result checkPrivilege(const std::string &privilege);
virtual RequestId popupRequest(const PopupCallbackClosure &closure,
const std::string &privilege);
+ virtual bool popupRequestInProgress(const std::string &privilege) const;
void updateConnection(Protocol::ConnectionFd fd, int mask);
void popupResponse(Protocol::RequestId id, int response);
private:
+ void respondToAllRequests(askuser_call_cause cause, askuser_popup_result result);
+
StatusCallbackClosure m_statusClosure;
std::unique_ptr<Protocol::ClientChannel> m_channel;
- std::map<RequestId, PopupCallbackClosure> m_callbacks;
+ std::map<RequestId, PopupCallbackClosure> m_popupClosures;
+ std::set<std::string> m_requestedPrivileges;
};
} // namespace Client
#pragma once
+#include <string>
+
#include <askuser-notification-client.h>
namespace AskUser {
class PopupCallbackClosure {
public:
- PopupCallbackClosure(askuser_popup_response_callback callback, void *userData)
+ PopupCallbackClosure(askuser_popup_response_callback callback, const char *privilege, void *userData)
: m_callback(callback)
+ , m_privilege(privilege)
, m_userData(userData)
{}
void operator()(int requestId, askuser_call_cause cause, askuser_popup_result result) const
{
- m_callback(requestId, cause, result, m_userData);
+ m_callback(requestId, cause, result, m_privilege.c_str(), m_userData);
+ }
+
+ const std::string &privilege() const {
+ return m_privilege;
}
private:
askuser_popup_response_callback m_callback;
+ std::string m_privilege;
void *m_userData;
};
/*! \brief indicating that a connection error occurred */
#define ASKUSER_API_CONNECTION_ERROR -4
+/*! \brief indicating that a request has already been sent */
+#define ASKUSER_API_ALREADY_IN_PROGRESS -5
+
/** @} */
/**
* askuser_client_popup_request(). This should be
* interpreted as a valid value only if cause is equal to
* askuser_call_cause::ASKUSER_CALL_CAUSE_ANSWER.
+ * \param[in] privilege A privilege that has been checked.
* \param[in] p_user_data User specific data, this parameter was previously
* passed to askuser_client_popup_request().
*/
typedef void (*askuser_popup_response_callback) (int request_id,
askuser_call_cause cause,
askuser_popup_result result,
+ const char *privilege,
void *p_user_data);
/**