Provide for tracking all WakeLock usage.

Simplify WakeLocks use by pushing.

Correct fault in IMAP IDLE WakeLock usage.  The ThreadLocal in
MessagingControllerPushReceiver meant that the WakeLock acquired when
the DONE was sent was not being released when entering back into IDLE
state.

Consolidate the account notification so that all Activities use the
methods in MessagingController.
This commit is contained in:
Daniel Applebaum 2010-05-17 00:30:32 +00:00
parent 71c43b9634
commit 9cf42ef913
11 changed files with 217 additions and 85 deletions

View file

@ -39,6 +39,8 @@ import android.util.Log;
import com.fsck.k9.activity.FolderList;
import com.fsck.k9.activity.MessageList;
import com.fsck.k9.helper.power.TracingPowerManager;
import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.FetchProfile;
import com.fsck.k9.mail.Flag;
@ -4074,15 +4076,16 @@ public class MessagingController implements Runnable
final MessagingListener listener)
{
WakeLock twakeLock = null;
TracingWakeLock twakeLock = null;
if (useManualWakeLock)
{
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
twakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "K9");
TracingPowerManager pm = TracingPowerManager.getPowerManager(context);
twakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "K9 MessagingController.checkMail");
twakeLock.setReferenceCounted(false);
twakeLock.acquire(K9.MANUAL_WAKE_LOCK_TIMEOUT);
}
final WakeLock wakeLock = twakeLock;
final TracingWakeLock wakeLock = twakeLock;
for (MessagingListener l : getListeners())
{
@ -4592,6 +4595,7 @@ public class MessagingController implements Runnable
NotificationManager notifMgr =
(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
notifMgr.cancel(account.getAccountNumber());
notifMgr.cancel(-1000 - account.getAccountNumber());
}

View file

@ -5,6 +5,9 @@ import android.content.Context;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import com.fsck.k9.helper.power.TracingPowerManager;
import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
import com.fsck.k9.mail.Folder;
import com.fsck.k9.mail.Folder.OpenMode;
import com.fsck.k9.mail.Message;
@ -14,6 +17,8 @@ import com.fsck.k9.mail.store.LocalStore.LocalFolder;
import com.fsck.k9.service.SleepService;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
public class MessagingControllerPushReceiver implements PushReceiver
@ -28,42 +33,6 @@ public class MessagingControllerPushReceiver implements PushReceiver
controller = nController;
mApplication = nApplication;
}
ThreadLocal<WakeLock> threadWakeLock = new ThreadLocal<WakeLock>();
public void acquireWakeLock()
{
WakeLock wakeLock = threadWakeLock.get();
if (wakeLock == null)
{
PowerManager pm = (PowerManager) mApplication.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "K9");
wakeLock.setReferenceCounted(false);
threadWakeLock.set(wakeLock);
}
wakeLock.acquire(K9.PUSH_WAKE_LOCK_TIMEOUT);
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "Acquired WakeLock for Pushing for thread " + Thread.currentThread().getName());
}
public void releaseWakeLock()
{
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "Considering releasing WakeLock for Pushing");
WakeLock wakeLock = threadWakeLock.get();
if (wakeLock != null)
{
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "Releasing WakeLock for Pushing for thread " + Thread.currentThread().getName());
wakeLock.release();
}
else
{
Log.e(K9.LOG_TAG, "No WakeLock waiting to be released for thread " + Thread.currentThread().getName());
}
}
public void messagesFlagsChanged(Folder folder,
List<Message> messages)
@ -115,9 +84,10 @@ public class MessagingControllerPushReceiver implements PushReceiver
}
}
public void sleep(long millis)
@Override
public void sleep(TracingWakeLock wakeLock, long millis)
{
SleepService.sleep(mApplication, millis, threadWakeLock.get(), K9.PUSH_WAKE_LOCK_TIMEOUT);
SleepService.sleep(mApplication, millis, wakeLock, K9.PUSH_WAKE_LOCK_TIMEOUT);
}
public void pushError(String errorMessage, Exception e)
@ -164,4 +134,10 @@ public class MessagingControllerPushReceiver implements PushReceiver
}
}
@Override
public Context getContext()
{
return mApplication;
}
}

View file

@ -2,7 +2,6 @@ package com.fsck.k9.activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.NotificationManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -24,6 +23,8 @@ import com.fsck.k9.*;
import com.fsck.k9.Account.FolderMode;
import com.fsck.k9.activity.setup.AccountSettings;
import com.fsck.k9.activity.setup.FolderSettings;
import com.fsck.k9.helper.power.TracingPowerManager;
import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.Folder;
import com.fsck.k9.mail.Message;
@ -175,8 +176,8 @@ public class FolderList extends K9ListActivity
private void checkMail(FolderInfoHolder folder)
{
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
final WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email - UpdateWorker");
TracingPowerManager pm = TracingPowerManager.getPowerManager(this);
final TracingWakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "FolderList checkMail");
wakeLock.setReferenceCounted(false);
wakeLock.acquire(K9.WAKE_LOCK_TIMEOUT);
MessagingListener listener = new MessagingListener()
@ -285,6 +286,7 @@ public class FolderList extends K9ListActivity
boolean fromNotification = intent.getBooleanExtra(EXTRA_FROM_NOTIFICATION, false);
if (fromNotification && mAccount.goToUnreadMessageSearch())
{
MessagingController.getInstance(getApplication()).notifyAccountCancel(this, mAccount);
openUnreadSearch(this, mAccount);
finish();
}
@ -348,10 +350,7 @@ public class FolderList extends K9ListActivity
onRefresh(!REFRESH_REMOTE);
NotificationManager notifMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notifMgr.cancel(mAccount.getAccountNumber());
notifMgr.cancel(-1000 - mAccount.getAccountNumber());
MessagingController.getInstance(getApplication()).notifyAccountCancel(this, mAccount);
}

View file

@ -3,7 +3,6 @@ package com.fsck.k9.activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.NotificationManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -507,10 +506,9 @@ public class MessageList
if (mFolderName != null)
{
mController.listLocalMessagesSynchronous(mAccount, mFolderName, mAdapter.mListener);
mController.notifyAccountCancel(this, mAccount);
NotificationManager notifMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notifMgr.cancel(mAccount.getAccountNumber());
notifMgr.cancel(-1000 - mAccount.getAccountNumber());
MessagingController.getInstance(getApplication()).notifyAccountCancel(this, mAccount);
mController.getFolderUnreadMessageCount(mAccount, mFolderName, mAdapter.mListener);
}

View file

@ -0,0 +1,138 @@
package com.fsck.k9.helper.power;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicInteger;
import com.fsck.k9.K9;
import android.content.Context;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
public class TracingPowerManager
{
private final static boolean TRACE = true;
public static AtomicInteger wakeLockId = new AtomicInteger(0);
PowerManager pm = null;
private static TracingPowerManager tracingPowerManager;
private Timer timer;
public static synchronized TracingPowerManager getPowerManager(Context context)
{
if (tracingPowerManager == null)
{
if (K9.DEBUG)
{
Log.i(K9.LOG_TAG, "Creating TracingPowerManager");
}
tracingPowerManager = new TracingPowerManager(context);
}
return tracingPowerManager;
}
private TracingPowerManager(Context context)
{
pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (TRACE)
{
timer = new Timer();
}
}
public TracingWakeLock newWakeLock(int flags, String tag)
{
return new TracingWakeLock(flags, tag);
}
public class TracingWakeLock
{
WakeLock wakeLock = null;
int id;
String tag;
TimerTask timerTask;
public TracingWakeLock(int flags, String ntag)
{
tag = ntag;
wakeLock = pm.newWakeLock(flags, tag);
id = wakeLockId.getAndIncrement();
if (K9.DEBUG)
{
Log.i(K9.LOG_TAG, "Creating TracingWakeLock for tag " + tag + " with id " + id);
}
}
public void acquire(long timeout)
{
if (K9.DEBUG)
{
Log.i(K9.LOG_TAG, "Acquiring TracingWakeLock for tag " + tag + " and id " + id
+ " for " + timeout + " ms");
}
raiseNotification();
wakeLock.acquire(timeout);
}
public void acquire()
{
if (K9.DEBUG)
{
Log.i(K9.LOG_TAG, "Acquiring TracingWakeLock for tag " + tag + " and id " + id
+ " with no timeout");
}
raiseNotification();
wakeLock.acquire();
}
public void setReferenceCounted(boolean counted)
{
wakeLock.setReferenceCounted(counted);
}
public void release()
{
if (K9.DEBUG)
{
Log.i(K9.LOG_TAG, "Releasing TracingWakeLock for tag " + tag + " and id " + id );
}
wakeLock.release();
cancelNotification();
}
private void cancelNotification()
{
if (timer != null)
{
synchronized(timer)
{
if (timerTask != null)
{
timerTask.cancel();
}
}
}
}
private void raiseNotification()
{
if (timer != null)
{
synchronized(timer)
{
if (timerTask != null)
{
timerTask.cancel();
timerTask = null;
}
timerTask = new TimerTask()
{
@Override
public void run()
{
Log.i(K9.LOG_TAG, "TracingWakeLock for tag " + tag + " and id " + id + " still active");
}
};
timer.schedule(timerTask, 1000, 1000);
}
}
}
}
}

View file

@ -2,10 +2,13 @@ package com.fsck.k9.mail;
import java.util.List;
import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
import android.content.Context;
public interface PushReceiver
{
public void acquireWakeLock();
public void releaseWakeLock();
public Context getContext();
public void syncFolder(Folder folder);
public void messagesArrived(Folder folder, List<Message> mess);
public void messagesFlagsChanged(Folder folder, List<Message> mess);
@ -13,5 +16,5 @@ public interface PushReceiver
public String getPushState(String folderName);
public void pushError(String errorMessage, Exception e);
public void setPushActive(String folderName, boolean enabled);
public void sleep(long millis);
public void sleep(TracingWakeLock wakeLock, long millis);
}

View file

@ -4,11 +4,14 @@ package com.fsck.k9.mail.store;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.PowerManager;
import android.util.Log;
import com.fsck.k9.Account;
import com.fsck.k9.K9;
import com.fsck.k9.PeekableInputStream;
import com.fsck.k9.Utility;
import com.fsck.k9.helper.power.TracingPowerManager;
import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
import com.fsck.k9.mail.*;
import com.fsck.k9.mail.internet.*;
import com.fsck.k9.mail.store.ImapResponseParser.ImapList;
@ -2623,17 +2626,22 @@ public class ImapStore extends Store
final AtomicInteger idleFailureCount = new AtomicInteger(0);
final AtomicBoolean needsPoll = new AtomicBoolean(false);
List<ImapResponse> storedUntaggedResponses = new ArrayList<ImapResponse>();
TracingWakeLock wakeLock = null;
public ImapFolderPusher(ImapStore store, String name, PushReceiver nReceiver)
{
super(store, name);
receiver = nReceiver;
TracingPowerManager pm = TracingPowerManager.getPowerManager(receiver.getContext());
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ImapFolderPusher " + store.getAccount().getDescription() + ":" + getName());
wakeLock.setReferenceCounted(false);
}
public void refresh() throws IOException, MessagingException
{
if (idling.get())
{
receiver.acquireWakeLock();
wakeLock.acquire(K9.PUSH_WAKE_LOCK_TIMEOUT);
sendDone();
}
}
@ -2662,7 +2670,7 @@ public class ImapStore extends Store
{
public void run()
{
receiver.acquireWakeLock();
wakeLock.acquire(K9.PUSH_WAKE_LOCK_TIMEOUT);
if (K9.DEBUG)
Log.i(K9.LOG_TAG, "Pusher starting for " + getLogId());
@ -2788,7 +2796,7 @@ public class ImapStore extends Store
}
catch (Exception e)
{
receiver.acquireWakeLock();
wakeLock.acquire(K9.PUSH_WAKE_LOCK_TIMEOUT);
storedUntaggedResponses.clear();
idling.set(false);
receiver.setPushActive(getName(), false);
@ -2809,7 +2817,7 @@ public class ImapStore extends Store
receiver.pushError("Push error for " + getName(), e);
Log.e(K9.LOG_TAG, "Got exception while idling for " + getLogId(), e);
int delayTimeInt = delayTime.get();
receiver.sleep(delayTimeInt);
receiver.sleep(wakeLock, delayTimeInt);
delayTimeInt *= 2;
if (delayTimeInt > MAX_DELAY_TIME)
{
@ -2839,7 +2847,7 @@ public class ImapStore extends Store
}
finally
{
receiver.releaseWakeLock();
wakeLock.release();
}
}
};
@ -3182,7 +3190,7 @@ public class ImapStore extends Store
{
if (started == false)
{
receiver.acquireWakeLock();
wakeLock.acquire(K9.PUSH_WAKE_LOCK_TIMEOUT);
started = true;
}
@ -3204,7 +3212,7 @@ public class ImapStore extends Store
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "Idling " + getLogId());
receiver.releaseWakeLock();
wakeLock.release();
}
}
}

View file

@ -12,6 +12,8 @@ import android.os.PowerManager.WakeLock;
import android.util.Log;
import com.fsck.k9.K9;
import com.fsck.k9.helper.power.TracingPowerManager;
import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
public class CoreReceiver extends BroadcastReceiver
{
@ -20,13 +22,13 @@ public class CoreReceiver extends BroadcastReceiver
public static String WAKE_LOCK_ID = "com.fsck.k9.service.CoreReceiver.wakeLockId";
private static ConcurrentHashMap<Integer, WakeLock> wakeLocks = new ConcurrentHashMap<Integer, WakeLock>();
private static ConcurrentHashMap<Integer, TracingWakeLock> wakeLocks = new ConcurrentHashMap<Integer, TracingWakeLock>();
private static AtomicInteger wakeLockSeq = new AtomicInteger(0);
private static Integer getWakeLock(Context context)
{
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "K9");
TracingPowerManager pm = TracingPowerManager.getPowerManager(context);
TracingWakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "CoreReceiver getWakeLock");
wakeLock.setReferenceCounted(false);
wakeLock.acquire(K9.BOOT_RECEIVER_WAKE_LOCK_TIMEOUT);
Integer tmpWakeLockId = wakeLockSeq.getAndIncrement();
@ -40,7 +42,7 @@ public class CoreReceiver extends BroadcastReceiver
{
if (wakeLockId != null)
{
WakeLock wl = wakeLocks.remove(wakeLockId);
TracingWakeLock wl = wakeLocks.remove(wakeLockId);
if (wl != null)
{
if (K9.DEBUG)

View file

@ -13,12 +13,14 @@ import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import com.fsck.k9.K9;
import com.fsck.k9.helper.power.TracingPowerManager;
import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
public abstract class CoreService extends Service
{
public static String WAKE_LOCK_ID = "com.fsck.k9.service.CoreService.wakeLockId";
private static ConcurrentHashMap<Integer, WakeLock> wakeLocks = new ConcurrentHashMap<Integer, WakeLock>();
private static ConcurrentHashMap<Integer, TracingWakeLock> wakeLocks = new ConcurrentHashMap<Integer, TracingWakeLock>();
private static AtomicInteger wakeLockSeq = new AtomicInteger(0);
private ExecutorService threadPool = null;
private final String className = getClass().getName();
@ -43,8 +45,8 @@ public abstract class CoreService extends Service
protected static void addWakeLock(Context context, Intent i)
{
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "K9");
TracingPowerManager pm = TracingPowerManager.getPowerManager(context);
TracingWakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "CoreService addWakeLock");
wakeLock.setReferenceCounted(false);
wakeLock.acquire(K9.MAIL_SERVICE_WAKE_LOCK_TIMEOUT);
@ -59,9 +61,8 @@ public abstract class CoreService extends Service
@Override
public void onStart(Intent intent, int startId)
{
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "K9");
TracingPowerManager pm = TracingPowerManager.getPowerManager(this);
TracingWakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "CoreService onStart");
wakeLock.setReferenceCounted(false);
wakeLock.acquire(K9.MAIL_SERVICE_WAKE_LOCK_TIMEOUT);
@ -78,7 +79,7 @@ public abstract class CoreService extends Service
{
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "Got core wake lock id " + coreWakeLockId);
WakeLock coreWakeLock = wakeLocks.remove(coreWakeLockId);
TracingWakeLock coreWakeLock = wakeLocks.remove(coreWakeLockId);
if (coreWakeLock != null)
{
if (K9.DEBUG)
@ -105,8 +106,8 @@ public abstract class CoreService extends Service
public void execute(Context context, final Runnable runner, int wakeLockTime, final Integer startId)
{
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
final WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "K9");
TracingPowerManager pm = TracingPowerManager.getPowerManager(context);
final TracingWakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "CoreService execute");
wakeLock.setReferenceCounted(false);
wakeLock.acquire(wakeLockTime);

View file

@ -7,6 +7,8 @@ import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import com.fsck.k9.*;
import com.fsck.k9.helper.power.TracingPowerManager;
import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
import java.util.HashMap;
@ -80,17 +82,17 @@ public class PollService extends CoreService
class Listener extends MessagingListener
{
HashMap<String, Integer> accountsChecked = new HashMap<String, Integer>();
private WakeLock wakeLock = null;
private TracingWakeLock wakeLock = null;
private int startId = -1;
// wakelock strategy is to be very conservative. If there is any reason to release, then release
// don't want to take the chance of running wild
public synchronized void wakeLockAcquire()
{
WakeLock oldWakeLock = wakeLock;
TracingWakeLock oldWakeLock = wakeLock;
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "K9");
TracingPowerManager pm = TracingPowerManager.getPowerManager(PollService.this);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PollService wakeLockAcquire");
wakeLock.setReferenceCounted(false);
wakeLock.acquire(K9.WAKE_LOCK_TIMEOUT);

View file

@ -5,6 +5,7 @@ import android.content.Intent;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import com.fsck.k9.K9;
import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
@ -22,7 +23,7 @@ public class SleepService extends CoreService
private static AtomicInteger latchId = new AtomicInteger();
public static void sleep(Context context, long sleepTime, WakeLock wakeLock, long wakeLockTimeout)
public static void sleep(Context context, long sleepTime, TracingWakeLock wakeLock, long wakeLockTimeout)
{
Integer id = latchId.getAndIncrement();
if (K9.DEBUG)
@ -47,8 +48,8 @@ public class SleepService extends CoreService
}
try
{
boolean timedOut = latch.await(sleepTime, TimeUnit.MILLISECONDS);
if (timedOut == false)
boolean countedDown = latch.await(sleepTime, TimeUnit.MILLISECONDS);
if (countedDown == false)
{
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "SleepService latch timed out for id = " + id + ", thread " + Thread.currentThread().getName());
@ -110,7 +111,7 @@ public class SleepService extends CoreService
private static void reacquireWakeLock(SleepDatum sleepDatum)
{
WakeLock wakeLock = sleepDatum.wakeLock;
TracingWakeLock wakeLock = sleepDatum.wakeLock;
if (wakeLock != null)
{
synchronized (wakeLock)
@ -137,7 +138,7 @@ public class SleepService extends CoreService
private static class SleepDatum
{
CountDownLatch latch;
WakeLock wakeLock;
TracingWakeLock wakeLock;
long timeout;
}