Adjust server-side logic to use one popup with many privileges 88/180388/31
authorTomasz Swierczek <t.swierczek@samsung.com>
Tue, 29 May 2018 05:19:28 +0000 (07:19 +0200)
committerTomasz Swierczek <t.swierczek@samsung.com>
Tue, 28 Aug 2018 05:00:10 +0000 (05:00 +0000)
Change-Id: Ie15a6affd059f9b48457e35722812774da23bb8a

src/notification-daemon/Logic.cpp
src/notification-daemon/Logic.h
src/notification-daemon/PolicyUpdater.cpp
src/notification-daemon/PolicyUpdater.h
src/notification-daemon/event/Event.h
src/notification-daemon/ui/Popupper.cpp
src/notification-daemon/ui/Popupper.h

index 3e16add..f7b305b 100644 (file)
@@ -209,26 +209,18 @@ Eina_Bool Logic::processChannel(int fd, int mask) {
 }
 
 void Logic::addEvent(Protocol::ConnectionFd fd, Protocol::RequestId id,
-                     const std::map<Privilege, std::vector<Privacy>> &privsToAskablePrivacies,
-                     const std::map<Privilege, Policy> &privsToPolicy,
-                     const std::vector<Privilege> &privs,
-                     const std::vector<Privacy> &privacies) {
+                     const std::vector<Privacy> &privacies,
+                     const std::vector<PrivilegeStruct> &privilegesStructure) {
     EventId eventId{fd, id};
     auto &ev = m_eventInfo[eventId];
-    PrivaciesSequence &seq = ev.privaciesSeq;
-    seq.setPrivacies(privacies);
 
-    ev.privilegesAskablePrivacies = privsToAskablePrivacies;
-    ev.privilegesPolicy = privsToPolicy;
-    ev.privileges = privs;
+    ev.uniquePrivacies = privacies;
+    ev.privilegesStructure = privilegesStructure;
     ev.privacyResponses.clear();
 
     ConnectionInfo &conn = m_connToInfo[fd];
 
-    Privacy currentPrivacy;
-    seq.getNextPrivacy(currentPrivacy);
-
-    FdEvent fdEvent{eventId, std::unique_ptr<IUIEvent>(new EventPopupCheck(&m_popupper, conn.pkgId, currentPrivacy))};
+    FdEvent fdEvent{eventId, std::unique_ptr<IUIEvent>(new EventPopupCheck(&m_popupper, conn.pkgId, privacies))};
     m_pendingEvents.emplace_back(std::move(fdEvent));
 }
 
@@ -245,25 +237,27 @@ void Logic::popup(Protocol::ConnectionFd fd, Protocol::RequestId id, const std::
         }
         ConnectionInfo &conn = it->second;
         PkgMgrAppInfo appInfo;
-        std::map<Privilege, std::vector<Privacy>> privsToAskablePrivacies;
-        std::map<Privilege, Policy> privsToPolicy;
         std::set<Privacy> uniquePrivacies;
+        std::vector<PrivilegeStruct> privilegesStructure;
 
         for (auto &privilege : privileges) {
+            PrivilegeStruct privStruct;
+            privStruct.privilege = privilege;
             PrivilegePolicy privPolicy(conn.appId, privilege);
-            privsToPolicy[privilege] = privPolicy.calculatePolicy(appInfo);
-            ALOGD("Privilege " << privilege << " policy level calculated to : " << privsToPolicy[privilege]);
-            if (privsToPolicy[privilege] == "Ask user") {
-                privsToAskablePrivacies[privilege] = privPolicy.calculateAskablePrivacies(appInfo);
-                if (privsToAskablePrivacies[privilege].empty()) {
+            privStruct.policy = privPolicy.calculatePolicy(appInfo);
+            ALOGD("Privilege " << privilege << " policy level calculated to : " << privStruct.policy);
+            if (privStruct.policy == "Ask user") {
+                privStruct.askablePrivacies = privPolicy.calculateAskablePrivacies(appInfo);
+                if (privStruct.askablePrivacies.empty()) {
                     ALOGE("All privacies for privilege " << privilege << " are already allowed");
-                    privsToPolicy[privilege] = "Allow";
+                    privStruct.policy = "Allow";
                 } else {
-                    for (auto &privacy : privsToAskablePrivacies[privilege])
+                    for (auto &privacy : privStruct.askablePrivacies)
                         uniquePrivacies.insert(privacy);
                 }
 
             }
+            privilegesStructure.push_back(std::move(privStruct));
         }
 
         if (uniquePrivacies.empty()) {
@@ -271,12 +265,12 @@ void Logic::popup(Protocol::ConnectionFd fd, Protocol::RequestId id, const std::
             std::vector<int> responses;
             responses.resize(privileges.size());
             for (size_t i = 0; i < privileges.size(); ++i) {
-                if (privsToPolicy[privileges[i]] == "Allow") {
+                if (privilegesStructure[i].policy == "Allow") {
                     responses[i] = ASKUSER_ALLOW_FOREVER;
-                } else if (privsToPolicy[privileges[i]] == "Deny") {
+                } else if (privilegesStructure[i].policy == "Deny") {
                     responses[i] = ASKUSER_DENY_FOREVER;
                 } else {
-                    ALOGE("Unknown policy set : " << privsToPolicy[privileges[i]] << " for (" << conn.appId << ", " << conn.user
+                    ALOGE("Unknown policy set : " << privilegesStructure[i].policy << " for (" << conn.appId << ", " << conn.user
                           << ", " << privileges[i] << ")");
                     responses[i] = ASKUSER_DENY_ONCE;
                 }
@@ -287,7 +281,7 @@ void Logic::popup(Protocol::ConnectionFd fd, Protocol::RequestId id, const std::
 
         // we do have privacies to ask about, we need to generate event
         std::vector<Privacy> privacies(uniquePrivacies.begin(), uniquePrivacies.end());
-        addEvent(fd, id, privsToAskablePrivacies, privsToPolicy, privileges, privacies);
+        addEvent(fd, id, privacies, privilegesStructure);
         processEvents();
 
     } catch (const std::exception &e) {
@@ -406,7 +400,7 @@ void Logic::init() {
     init_agent_log();
     m_popupper.initialize();
     Po::setLocale();
-    m_popupper.registerPopupResponseHandler([&](NResponseType response) { popupResponse(response);});
+    m_popupper.registerPopupResponseHandler([&](std::vector<NResponseType> responses) { popupResponses(responses);});
 
     registerSignalFd();
 
@@ -421,24 +415,30 @@ void Logic::run() {
 
 bool Logic::setPolicy(const ConnectionInfo &conn) {
     ALOGD("Setting policy for app " << conn.appId);
-    for (auto &pr : m_eventInfo[m_currentEvent].privacyResponses) {
-        const auto &level = clientResponseToPolicy(pr.second);
-        if (!PolicyUpdater::update(conn.appId, pr.first, level)) {
-            ALOGE("Couldn't set policy for " << conn.appId << " privacy : " << pr.first << " level : " << level);
-            return false;
-        }
+    auto &currentEvent = m_eventInfo[m_currentEvent];
+    std::vector<std::string> levels(currentEvent.uniquePrivacies.size());
+
+    for (size_t i = 0; i < levels.size(); ++i) {
+        const auto &privacy = currentEvent.uniquePrivacies[i];
+        levels[i] = clientResponseToPolicy(currentEvent.privacyResponses[privacy]);
     }
+
+    if (!PolicyUpdater::update(conn.appId, currentEvent.uniquePrivacies, levels)) {
+        ALOGE("Couldn't set policy for " << conn.appId);
+        return false;
+    }
+
     return true;
 }
 
 void Logic::processResponse(const ConnectionInfo &conn) {
     auto &currentEvent = m_eventInfo[m_currentEvent];
-    std::vector<int> responses(currentEvent.privileges.size(), ASKUSER_UNKNOWN_ERROR);
+    std::vector<int> responses(currentEvent.privilegesStructure.size(), ASKUSER_UNKNOWN_ERROR);
 
     if (setPolicy(conn)) {
         for (size_t i = 0; i < responses.size(); ++i) {
-            const auto &privilege = currentEvent.privileges[i];
-            const auto &policy = currentEvent.privilegesPolicy[privilege];
+            const auto &privilegeStruct = currentEvent.privilegesStructure[i];
+            const auto &policy = privilegeStruct.policy;
             if (policy == "Allow") {
                 responses[i] = ASKUSER_ALLOW_FOREVER;
             } else if (policy == "Deny") {
@@ -449,61 +449,52 @@ void Logic::processResponse(const ConnectionInfo &conn) {
                 // Ask user policy - need to calcualte from existing responses to privacies
                 // but only privacies askable for this privilege should be used!
                 responses[i] = ASKUSER_ALLOW_FOREVER;
-                bool hasAnswer = false;
-                for (auto &privacy : currentEvent.privilegesAskablePrivacies[privilege]) {
-                    const auto &privResponses = currentEvent.privacyResponses;
-                    const auto privResponseIt = privResponses.find(privacy);
-                    if (privResponseIt != privResponses.end()) {
+                for (auto &privacy : privilegeStruct.askablePrivacies) {
+                    const auto &privResponseIt = currentEvent.privacyResponses.find(privacy);
+                    if (privResponseIt != currentEvent.privacyResponses.end()) {
                         responses[i] = std::min(privResponseIt->second, responses[i]);
-                        hasAnswer = true;
+                    }
+                    else {
+                        ALOGE("Unable to response for askable privacy: " << privacy);
+                        responses[i] = ASKUSER_DENY_ONCE;
+                        break;
                     }
                 }
-                if (!hasAnswer)
-                    responses[i] = ASKUSER_DENY_ONCE;
             }
         }
     }
     m_serverChannel->popupResponses(m_currentEvent.fd, m_currentEvent.id, std::move(responses));
 }
 
-void Logic::popupResponse(NResponseType response) {
+void Logic::popupResponses(const std::vector<NResponseType> &responses) {
     auto it = m_connToInfo.find(m_currentEvent.fd);
+
     if (it == m_connToInfo.end()) {
         ALOGE("Got response from inactive fd " << m_currentEvent.fd);
         return;
     }
+
     ConnectionInfo &conn = it->second;
-    PrivaciesSequence &seq = m_eventInfo[m_currentEvent].privaciesSeq;
-    int clientResponse = uiResponseToClientResponse(response);
+    auto &currentEvent = m_eventInfo[m_currentEvent];
 
-    std::string justAnsweredPrivacy;
-    if (!seq.getCurrentPrivacy(justAnsweredPrivacy)) {
-        ALOGE("Received response for unknown privacy - this should not happen");
+    if (responses.size() != currentEvent.uniquePrivacies.size()) {
+        ALOGE("Got invalid number of responses: " << responses.size() << " but expected: "
+                << currentEvent.uniquePrivacies.size());
         finishCurrentRequest();
         processEvents();
         return;
     }
-    m_eventInfo[m_currentEvent].privacyResponses[justAnsweredPrivacy] = clientResponse;
-    if (clientResponse != ASKUSER_ALLOW_FOREVER && m_eventInfo[m_currentEvent].privileges.size() == 1) {
-        // request for only 1 privilege is being processed and at least 1 privacy is not allowed
-        // stop iteration over privacies, its pointless as the privilege is alraedy dissallowed
-        processResponse(conn);
-        finishCurrentRequest();
-    } else {
-        // request for many privileges is being processed or one privilege but still needs to be processed
-        Privacy nextPrivacy;
-        if (seq.getNextPrivacy(nextPrivacy)) {
-            // More privacies to process - replace existing event with new privacy
-            FdEvent fdEvent{m_currentEvent, std::unique_ptr<IUIEvent>(new EventPopupCheck(&m_popupper, conn.pkgId, nextPrivacy))};
-            m_pendingEvents[0] = std::move(fdEvent);
-            // don't call finishCurrentRequest here, because it will pop event, which we replaced
-            m_currentEvent = EventId();
-        } else {
-            // No more privacies, request is ready for response
-            processResponse(conn);
-            finishCurrentRequest();
-        }
+
+    for (size_t i = 0; i < responses.size(); ++i) {
+        int clientResponse = uiResponseToClientResponse(responses[i]);
+        const auto &privacy = currentEvent.uniquePrivacies[i];
+        ALOGD("Client response for privacy " << privacy << " is " << clientResponse);
+        currentEvent.privacyResponses[privacy] = clientResponse;
     }
+
+    // No more privacies, since all are answered by one popup - request is ready for response
+    processResponse(conn);
+    finishCurrentRequest();
     processEvents();
 }
 
index e05c405..5e4a10a 100644 (file)
@@ -29,7 +29,6 @@
 #include <Elementary.h>
 
 #include "event/Event.h"
-#include "PrivaciesSequence.h"
 
 namespace AskUser {
 
@@ -76,6 +75,12 @@ private:
         std::string user;
     };
 
+    struct PrivilegeStruct {
+        Privilege privilege;
+        Policy policy;
+        std::vector<Privacy> askablePrivacies;
+    };
+
     //Initialization
     void registerSignalFd();
     void prepareChannel();
@@ -88,10 +93,8 @@ private:
     //static Eina_Bool signalHandler(void *data, int type, void *event);
 
     void addEvent(Protocol::ConnectionFd fd, Protocol::RequestId id,
-                  const std::map<Privilege, std::vector<Privacy>> &privsToAskablePrivacies,
-                  const std::map<Privilege, Policy> &privsToPolicy,
-                  const std::vector<Privilege> &privs,
-                  const std::vector<Privacy> &privacies);
+                  const std::vector<Privacy> &privacies,
+                  const std::vector<PrivilegeStruct> &privilegesStructure);
     Eina_Bool processChannel(int fd, int mask);
     bool identifyClient(const std::string &label, std::string &appId, std::string &pkgId);
 
@@ -103,7 +106,7 @@ private:
     void startTimer();
     void stopTimer();
 
-    void popupResponse(NResponseType response);
+    void popupResponses(const std::vector<NResponseType> &response);
 
     bool processError(EventId id, int error);
     bool setPolicy(const ConnectionInfo &conn);
@@ -136,10 +139,9 @@ private:
     std::map<Protocol::ConnectionFd, ConnectionInfo> m_connToInfo;
 
     struct EventInfo {
-        PrivaciesSequence privaciesSeq;
-        std::vector<Privilege> privileges;
-        std::map<Privilege, std::vector<Privacy>> privilegesAskablePrivacies;
-        std::map<Privilege, Policy> privilegesPolicy;
+        std::vector<Privacy> uniquePrivacies; // privacies placement order is important,
+        // UI will only send back responses, so then Logic has to map responses to privacies
+        std::vector<PrivilegeStruct> privilegesStructure;
         std::map<Privacy, int> privacyResponses;
     };
 
index fdf2e15..c99ec05 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2016-2018 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
 /**
  * @file        PolicyUpdater.cpp
  * @author      Zofia Abramowska <z.abramowska@samsung.com>
+ * @author      Tomasz Swierczek <t.swierczek@samsung.com>
  * @brief       This file implements class of policy updater
  */
 
@@ -33,37 +34,50 @@ namespace AskUser {
 
 namespace Notification {
 
-bool PolicyUpdater::update(const std::string &appId,
-                           const std::string &privacy, const std::string &level)
+bool PolicyUpdater::update(const std::string &appId, const std::vector<std::string> &privacies,
+                           const std::vector<std::string> &levels)
 {
     try {
-        ALOGD("Generating policy update for: app: " << appId << ", privacy: " << privacy
-              << ", user:" << geteuid() << ", level: " << level);
+        ALOGD("Generating policy update for: app: " << appId << ", user:" << geteuid()
+              << ", privacies num: " << privacies.size());
+
+        if (privacies.size() != levels.size() || levels.size() == 0) {
+            ALOGE("Policy update for invalid parameres");
+            return false;
+        }
 
         static const std::string user = std::to_string(geteuid());
         PolicyRequest req;
 
-        auto privacyPrivs = PrivilegeInfo::getPrivacyPrivileges(privacy);
-        if (privacyPrivs.empty()) {
-            ALOGE("Unable to get privacy privileges for privacy " << privacy);
-            throw Exception("Unable to get privacy privileges for privacy " + privacy);
-        }
+        for (size_t i = 0; i < privacies.size(); ++i) {
+            const auto &privacy = privacies[i];
+            const auto &level = levels[i];
+
+            ALOGD("Generating policy update for: app: " << appId << ", user:" << geteuid()
+                  << ", privacy " << privacy << ", level: " << level);
+
+            auto privacyPrivs = PrivilegeInfo::getPrivacyPrivileges(privacy);
+            if (privacyPrivs.empty()) {
+                ALOGE("Unable to get privacy privileges for privacy " << privacy);
+                throw Exception("Unable to get privacy privileges for privacy " + privacy);
+            }
 
-        for (auto &priv : privacyPrivs) {
-            std::string currentPolicy = getPrivilegePolicy(appId, priv);
-            if (currentPolicy.empty()) {
-                ALOGD("Application didn't request privilege " << priv << ", skipping");
-                continue;
+            for (auto &priv : privacyPrivs) {
+                std::string currentPolicy = getPrivilegePolicy(appId, priv);
+                if (currentPolicy.empty()) {
+                    ALOGD("Application didn't request privilege " << priv << ", skipping");
+                    continue;
+                }
+                ALOGD("Adding policy entries for : app: " << appId << ", priv: "
+                      << priv  << ", user:" << user << ", level: "
+                      << level);
+                PolicyEntry entry;
+                entry.setApp(appId);
+                entry.setUser(user);
+                entry.setPrivilege(priv);
+                entry.setLevel(level);
+                req.addEntry(std::move(entry));
             }
-            ALOGD("Adding policy entries for : app: " << appId << ", priv: "
-                  << priv  << ", user:" << user << ", level: "
-                  << level);
-            PolicyEntry entry;
-            entry.setApp(appId);
-            entry.setUser(user);
-            entry.setPrivilege(priv);
-            entry.setLevel(level);
-            req.addEntry(std::move(entry));
         }
 
         req.updatePolicy();
index f821fe0..8cc72a9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2016 - 2018 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
 /**
  * @file        PolicyUpdater.h
  * @author      Zofia Abramowska <z.abramowska@samsung.com>
+ * @author      Tomasz Swierczek <t.swierczek@samsung.com>
  * @brief       This file declares class of policy updater
  */
 
 #pragma once
 
-#include <atomic>
-#include <mutex>
 #include <string>
 #include <vector>
-#include <thread>
-#include <condition_variable>
 
 namespace AskUser {
 
 namespace Notification {
 
 namespace PolicyUpdater {
-    bool update(const std::string &appId, const std::string &privacy,
-                const std::string &level);
+    bool update(const std::string &appId, const std::vector<std::string> &privacies,
+                const std::vector<std::string> &levels);
 };
 
 } // namespace Agent
index 95e43a0..f0dbff0 100644 (file)
@@ -41,19 +41,16 @@ protected:
 
 class EventPopupCheck : public IUIEvent {
 public:
-    EventPopupCheck(Popupper *popupper, const std::string &pkgId, const std::string &privacy)
-        : IUIEvent(popupper), m_pkgId(pkgId)
-    {
-        //TODO: change in final commit to m_privacy(privacy)
-        m_privacy.push_back(privacy);
-    }
+    EventPopupCheck(Popupper *popupper, const std::string &pkgId, const std::vector<std::string> &privacies)
+        : IUIEvent(popupper), m_pkgId(pkgId), m_privacies(privacies)
+    {}
 
     virtual void process() {
-        m_popupper->popupCheck(m_pkgId, m_privacy);
+        m_popupper->popupCheck(m_pkgId, m_privacies);
     }
 private:
     std::string m_pkgId;
-    std::vector<std::string> m_privacy;
+    std::vector<std::string> m_privacies;
 };
 
 } //namespace AskUser
index d731cc6..0ce48ee 100644 (file)
@@ -97,8 +97,7 @@ void Popupper::buttonAnswer(IAnswerable::Button button) {
     m_responses.push_back(answer);
 
     if (m_responses.size() == m_privaciesSequence.size()) {
-        //TODO: change to m_responses in final commit
-        m_popupResponseHandler(m_responses[0]);
+        m_popupResponseHandler(m_responses);
         return;
     }
 
@@ -230,8 +229,7 @@ void Popupper::respondToRest(NResponseType response)
         m_responses.push_back(response);
         alreadyRespondedCount++;
     }
-    //TODO: CHANGE TO m_responses in final commit
-    m_popupResponseHandler(m_responses[0]);
+    m_popupResponseHandler(m_responses);
 }
 
 void Popupper::start()
index d6bd959..f9cb337 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <Elementary.h>
 #include <functional>
-#include <map>
 #include <memory>
 #include <string>
 #include <vector>
@@ -43,7 +42,7 @@ namespace Notification {
 
 class Popupper {
 public:
-    typedef std::function<void(NResponseType)> PopupHandler;
+    typedef std::function<void(const std::vector<NResponseType>&)> PopupHandler;
 
     Popupper() = default;
     void initialize();