Skip to content

Commit

Permalink
[msyncd] Ensure we allow device suspend after sync is triggered. Cont…
Browse files Browse the repository at this point in the history
…ributes to JB#34349

This commit ensures that the onBackgroundSyncCompleted() handler is
invoked when the sync status for an active background sync transitions
to a finished (error/done/cancelled) state.  This handler will stop
the background activity which prevents device suspend.

It also ensures that if no scheduled-sync-alarm can be set (e.g., if
no next scheduled time exists) that the background activity is also
stopped.  This can occur if the profile has peak (rush) schedule but
no off-peak (non-rush) schedule.

Together, these changes should ensure that msyncd doesn't prevent
device suspend for longer than it takes to complete its sync actions.

Contributes to JB#34349
  • Loading branch information
Chris Adams committed Aug 11, 2016
1 parent eb6bc83 commit f7561ea
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 17 deletions.
34 changes: 19 additions & 15 deletions msyncd/BackgroundSync.cpp
Expand Up @@ -101,12 +101,12 @@ bool BackgroundSync::set(const QString &aProfName, int seconds)
newAct.frequency = frequency;
newAct.backgroundActivity->setWakeupFrequency(newAct.frequency);
newAct.backgroundActivity->wait();
LOG_DEBUG("BackgroundSync::set(), Rescheduling for " << aProfName << " with frequency " << seconds / 60);
LOG_DEBUG("BackgroundSync::set() Rescheduling for" << aProfName << "with frequency" << (seconds / 60) << "minutes, waiting.");
return true;
} else {
newAct.backgroundActivity->wait();
LOG_DEBUG("Profile already with the same frequency... No new BackgroundSync");
return true; //returing 'true' - no immediate sync request to be sent.
LOG_DEBUG("BackgroundSync::set() Frequency unchanged for" << aProfName << ", waiting.");
return true; //returning 'true' - no immediate sync request to be sent.
}
}
}
Expand All @@ -116,14 +116,14 @@ bool BackgroundSync::set(const QString &aProfName, int seconds)
newAct.id = newAct.backgroundActivity->id();
connect(newAct.backgroundActivity,SIGNAL(running()), this, SLOT(onBackgroundSyncStarted()));
if (seconds / 60 > MAX_FREQUENCY) {
LOG_DEBUG("BackgroundSync::set() without a frequency, profile name = " << aProfName);
newAct.frequency = BackgroundActivity::Range; // 0
newAct.backgroundActivity->wait(seconds);
LOG_DEBUG("BackgroundSync::set() profile name =" << aProfName << "without a valid frequency, waiting for" << seconds << "seconds.");
} else {
newAct.frequency = frequencyFromSeconds(seconds);
newAct.backgroundActivity->setWakeupFrequency(newAct.frequency);
newAct.backgroundActivity->wait();
LOG_DEBUG("BackgroundSync::set(), profile name = " << aProfName << " with frequency " << seconds / 60);
LOG_DEBUG("BackgroundSync::set() profile name =" << aProfName << "with frequency " << (seconds / 60) << "minutes, waiting.");
}
return true;
}
Expand All @@ -137,17 +137,18 @@ void BackgroundSync::onBackgroundSyncStarted()
QString profName = getProfNameFromId(tempAct->id());

if (!profName.isEmpty()) {
LOG_DEBUG("Background Sync started, for profile = " << profName);
LOG_DEBUG("BackgroundSync started, for profile = " << profName);
emit onBackgroundSyncRunning(profName);
} else {
LOG_DEBUG("Error profile for background activity not found");
LOG_WARNING("BackgroundSync: Error: profile for background activity not found! Stopping background activity.");
tempAct->stop(); // but don't delete tempAct to avoid possible crash in later profile cleanup.
}
}

void BackgroundSync::onBackgroundSyncCompleted(QString aProfName)
{
FUNCTION_CALL_TRACE;
LOG_DEBUG("Background sync completed, removing activity, profile name = " << aProfName);
LOG_DEBUG("BackgroundSync completed, removing activity, profile name = " << aProfName);
remove(aProfName);
}

Expand Down Expand Up @@ -240,26 +241,28 @@ bool BackgroundSync::setSwitch(const QString &aProfName, const QDateTime &aSwitc
if(aProfName.isEmpty())
return false;

int switchSecs = QDateTime::currentDateTime().secsTo(aSwitchTime);
if(iScheduledSwitch.contains(aProfName) == true) {
BActivitySwitchStruct &newSwitch = iScheduledSwitch[aProfName];
if (newSwitch.nextSwitch != aSwitchTime) {
// If activity's state was already Waiting, the state doesn't change, nothing happens and
// the existing background activity keeps running until the previously set time expires, so we have to stop it.
newSwitch.backgroundActivity->stop();
newSwitch.nextSwitch = aSwitchTime;
newSwitch.backgroundActivity->wait(QDateTime::currentDateTime().secsTo(aSwitchTime));
LOG_DEBUG("BackgroundSync::setSwitch(), Rescheduling for " << aProfName << " at " << aSwitchTime.toString());
newSwitch.backgroundActivity->wait(switchSecs);
LOG_DEBUG("BackgroundSync::setSwitch() Rescheduling switch for" << aProfName << "at" << aSwitchTime.toString() << "(" << switchSecs << "secs ) waiting.");
} else {
LOG_DEBUG("Profile already with the same switch timer... No new switch timer");
newSwitch.backgroundActivity->wait(switchSecs);
LOG_DEBUG("BackgroundSync::setSwitch() Profile" << aProfName << "already with the same switch timer, at" << aSwitchTime.toString() << "(" << switchSecs << "secs ) waiting.");
}
} else {
BActivitySwitchStruct &newSwitch = iScheduledSwitch[aProfName];
newSwitch.backgroundActivity = new BackgroundActivity(this);
newSwitch.id = newSwitch.backgroundActivity->id();
connect(newSwitch.backgroundActivity,SIGNAL(running()), this, SLOT(onBackgroundSwitchStarted()));
newSwitch.nextSwitch = aSwitchTime;
newSwitch.backgroundActivity->wait(QDateTime::currentDateTime().secsTo(aSwitchTime));
LOG_DEBUG("BackgroundSync::setSwitch(), profile name = " << aProfName << " at " << aSwitchTime.toString());
newSwitch.backgroundActivity->wait(switchSecs);
LOG_DEBUG("BackgroundSync::setSwitch() Set switch for profile name =" << aProfName << "at" << aSwitchTime.toString() << "(" << switchSecs << "secs ) waiting.");
}
return true;
}
Expand All @@ -273,10 +276,11 @@ void BackgroundSync::onBackgroundSwitchStarted()
QString profName = getProfNameFromSwitchId(tempAct->id());

if (!profName.isEmpty()) {
LOG_DEBUG("Background switch timer started, for profile = " << profName);
LOG_DEBUG("BackgroundSync: switch timer started, for profile = " << profName);
emit onBackgroundSwitchRunning(profName);
} else {
LOG_DEBUG("Error profile for background switch timer not found");
LOG_WARNING("BackgroundSync: Error: profile for switch timer not found! Stopping background activity.");
tempAct->stop(); // but don't delete tempAct to avoid possible crash in later profile cleanup.
}
}

Expand Down
39 changes: 38 additions & 1 deletion msyncd/SyncScheduler.cpp
Expand Up @@ -28,6 +28,7 @@
#endif
#include "SyncScheduler.h"
#include "SyncProfile.h"
#include "SyncCommonDefs.h"
#include "LogMacros.h"
#include <QtDBus/QtDBus>

Expand Down Expand Up @@ -160,10 +161,31 @@ void SyncScheduler::removeProfile(const QString &aProfileName)
void SyncScheduler::doIPHeartbeatActions(QString aProfileName)
{
FUNCTION_CALL_TRACE;

iActiveBackgroundSyncProfiles.insert(aProfileName);
emit syncNow(aProfileName);
}

void SyncScheduler::syncStatusChanged(const QString &aProfileName, int aStatus,
const QString &aMessage, int aMoreDetails)
{
if (iActiveBackgroundSyncProfiles.contains(aProfileName) && aStatus >= Sync::SYNC_ERROR) {
// the background sync cycle is finished.
// tell the scheduler that it can stop preventing device suspend.
LOG_DEBUG("Background sync" << aProfileName << "finished with status:" << aStatus <<
"and extra:" << aMessage << "," << aMoreDetails);
iActiveBackgroundSyncProfiles.remove(aProfileName);
#ifdef USE_KEEPALIVE
iBackgroundActivity->onBackgroundSyncCompleted(aProfileName);
#endif

// and schedule the next background sync if necessary.
SyncProfile* profile = iProfileManager.syncProfile(aProfileName);
if (profile) {
setNextAlarm(profile);
}
}
}

#ifdef USE_KEEPALIVE
void SyncScheduler::rescheduleBackgroundActivity(const QString& aProfileName)
{
Expand Down Expand Up @@ -232,6 +254,21 @@ int SyncScheduler::setNextAlarm(const SyncProfile* aProfile, QDateTime aNextSync
}
}
else {
#ifdef USE_KEEPALIVE
// no valid next scheduled sync time for background sync.
// stop the background activity to allow device suspend.
iBackgroundActivity->remove(aProfile->name());
if (aProfile->rushEnabled()) {
QDateTime nextSyncSwitch = aProfile->nextRushSwitchTime(QDateTime::currentDateTime());
if (nextSyncSwitch.isValid()) {
iBackgroundActivity->setSwitch(aProfile->name(), nextSyncSwitch);
} else {
iBackgroundActivity->removeSwitch(aProfile->name());
}
} else {
iBackgroundActivity->removeSwitch(aProfile->name());
}
#endif
LOG_WARNING("Next sync time is not valid, sync not scheduled for profile"
<< aProfile->name());
}
Expand Down
17 changes: 17 additions & 0 deletions msyncd/SyncScheduler.h
Expand Up @@ -32,6 +32,8 @@
#endif
#include <QObject>
#include <QMap>
#include <QSet>
#include <QString>
#include <QDateTime>
#include <ctime>

Expand Down Expand Up @@ -93,6 +95,20 @@ class SyncScheduler : public QObject
*/
void removeProfile(const QString &aProfileName);

public slots:
/*! \brief Handles the sync status change signal from the synchronizer
*
* This allows the SyncScheduler to appropriately wait() or stop() any background
* activity which is preventing device suspend.
*
* @param aProfileName Name of the profile
* @param aStatus Status of the sync
* @param aMessage Status message as a string
* @param aMoreDetails In case of failure, contains detailed reason
*/
void syncStatusChanged(const QString &aProfileName, int aStatus,
const QString &aMessage, int aMoreDetails);

private slots:

#ifndef USE_KEEPALIVE
Expand Down Expand Up @@ -171,6 +187,7 @@ private slots:
/// BackgroundSync management object
BackgroundSync *iBackgroundActivity;
ProfileManager iProfileManager;
QSet<QString> iActiveBackgroundSyncProfiles;
#else
/// A list of sync schedule profiles
QMap<QString, int> iSyncScheduleProfiles;
Expand Down
3 changes: 2 additions & 1 deletion msyncd/synchronizer.cpp
Expand Up @@ -1610,7 +1610,7 @@ void Synchronizer::reschedule(const QString &aProfileName)
}
}

void Synchronizer::slotSyncStatus(QString aProfileName, int aStatus, QString /*aMessage*/, int /*aMoreDetails*/)
void Synchronizer::slotSyncStatus(QString aProfileName, int aStatus, QString aMessage, int aMoreDetails)
{
FUNCTION_CALL_TRACE;
SyncProfile *profile = iProfileManager.syncProfile(aProfileName);
Expand Down Expand Up @@ -1643,6 +1643,7 @@ void Synchronizer::slotSyncStatus(QString aProfileName, int aStatus, QString /*a
break;
}
}
iSyncScheduler->syncStatusChanged(aProfileName, aStatus, aMessage, aMoreDetails);
delete profile;
}
}
Expand Down

0 comments on commit f7561ea

Please sign in to comment.