* limitations under the License.
*/
+#include <algorithm>
+#include <JobContext.h>
+#include "ContextManager.h"
+#include "ContextPublisher.h"
+#include "JobRunner.h"
+#include "ActionState.h"
#include "ReqVerificationState.h"
+#define MIN_TIMEOUT 20u
+
using namespace ctx;
ReqVerificationState::ReqVerificationState(JobState* prevState) :
ReqVerificationState::~ReqVerificationState()
{
_EXIT;
+ __unsubscribe();
}
bool ReqVerificationState::execute()
{
- //TODO: Read the requirement contexts.
- // If all satisfied, goto ActionState.
- // If the RequirementTimeout == 0, goto restart the machine.
- // Set the timeout.
- // If the timeout expires, read the requirements again.
- // If all mandatory satisfied, goto ActionState, restart otherwise.
+ if (!__subscribe())
+ return false;
+
+ unsigned int timeout = std::max(getJobInfo()->getRequirementTimeout(), MIN_TIMEOUT);
+
+ g_idle_add(__onStart, this);
+ g_timeout_add(timeout, __onTimeout, this);
+
+ return true;
+}
+
+void ReqVerificationState::contextDataReady(ContextPublisher* pubs, void* userData)
+{
+ for (auto it = __reqInfos.begin(); it != __reqInfos.end(); ++it) {
+ if ((*it).pubs != pubs)
+ continue;
+
+ if (!(*((*it).req) <= pubs->getData()))
+ continue;
+
+ pubs->removeObserver(this);
+ __reqInfos.erase(it);
+ }
+
+ if (__inspectAll())
+ transit(new ActionState(this, false));
+}
+
+bool ReqVerificationState::__subscribe()
+{
+ auto& reqs = getJobInfo()->getRequirements();
+
+ for (auto& req : reqs) {
+ ContextPublisher* pubs = ContextManager::getPublisher(req->getUri(), getUid());
+ IF_FAIL_RETURN(pubs, false);
+
+ pubs->addObserver(this, req);
+ __reqInfos.emplace_back(req, pubs);
+ }
+
+ return true;
+}
+
+void ReqVerificationState::__unsubscribe()
+{
+ for (auto& info : __reqInfos) {
+ info.pubs->removeObserver(this);
+ }
+
+ __reqInfos.clear();
+}
+
+void ReqVerificationState::__readLatest()
+{
+ __reqInfos.remove_if(
+ [this](const ReqInfo& info)->bool {
+ if (!info.pubs->isReady())
+ return false;
+ if (!(*(info.req) <= info.pubs->getData()))
+ return false;
+ info.pubs->removeObserver(this);
+ return true;
+ });
+}
+
+bool ReqVerificationState::__inspectAll()
+{
+ if (getJobInfo()->isDisjunction()) {
+ bool satisfied = __inspectDisjunction();
+ if (satisfied)
+ __unsubscribe();
+ return satisfied;
+ }
+
+ return __reqInfos.empty();
+}
+
+bool ReqVerificationState::__inspectMandatory()
+{
+ if (getJobInfo()->isDisjunction())
+ return __inspectDisjunction();
+
+ for (auto& info : __reqInfos) {
+ if (!info.req->isOptional())
+ return false;
+ }
+
return true;
}
+
+bool ReqVerificationState::__inspectDisjunction()
+{
+ unsigned int all = getJobInfo()->getRequirements().size();
+ unsigned int remaining = __reqInfos.size();
+ return remaining < all;
+}
+
+void ReqVerificationState::__onStart()
+{
+ __readLatest();
+
+ if (__inspectAll())
+ transit(new ActionState(this, false));
+}
+
+void ReqVerificationState::__onTimeout()
+{
+ if (__inspectMandatory()) {
+ __unsubscribe();
+ transit(new ActionState(this, true));
+ return;
+ }
+
+ _I("Not all mandatory requirements are satisfied");
+ __unsubscribe();
+ getJobRunner()->restart();
+}
+
+gboolean ReqVerificationState::__onStart(gpointer data)
+{
+ static_cast<ReqVerificationState*>(data)->__onStart();
+ return G_SOURCE_REMOVE;
+}
+
+gboolean ReqVerificationState::__onTimeout(gpointer data)
+{
+ static_cast<ReqVerificationState*>(data)->__onTimeout();
+ return G_SOURCE_REMOVE;
+}
+
+ReqVerificationState::ReqInfo::ReqInfo(JobRequirement* r, ContextPublisher* p) :
+ req(r),
+ pubs(p)
+{
+}
#ifndef __CONTEXT_JOB_SCHEDULER_REQ_VERIFICATION_STATE_H__
#define __CONTEXT_JOB_SCHEDULER_REQ_VERIFICATION_STATE_H__
+#include <list>
#include <WakeLock.h>
+#include "IContextObserver.h"
#include "JobState.h"
namespace ctx {
- class ReqVerificationState : public JobState {
+ class ReqVerificationState : public JobState, public IContextObserver {
public:
ReqVerificationState(JobState* prevState);
~ReqVerificationState();
bool execute();
+ void contextDataReady(ContextPublisher* pubs, void* userData);
private:
+ bool __subscribe();
+ void __unsubscribe();
+ void __readLatest();
+
+ bool __inspectAll();
+ bool __inspectMandatory();
+
+ void __onStart();
+ void __onTimeout();
+
+ static gboolean __onStart(gpointer data);
+ static gboolean __onTimeout(gpointer data);
+
+ /* Legacy support */
+ bool __inspectDisjunction();
+
+ struct ReqInfo {
+ JobRequirement* req;
+ ContextPublisher* pubs;
+ ReqInfo(JobRequirement* r, ContextPublisher* p);
+ };
+ std::list<ReqInfo> __reqInfos;
WakeLock __wakeLock;
};