Bug 697987 - Remove race when downloading favicons [r=sriram]

Multiple DownloadFaviconTasks could get queued and run simultaneously,
making the tab's final favicon anybody's guess. Instead, this patch
ensures that existing favicon downloaders for a particular tab are
cancelled before new ones are queued, eliminating the race condition.
This commit is contained in:
Kartikaya Gupta 2011-11-01 13:15:08 -04:00
parent 1bdc567283
commit 368bd3af0d
2 changed files with 62 additions and 64 deletions

View File

@ -43,7 +43,6 @@ package org.mozilla.gecko;
import java.io.*;
import java.util.*;
import java.util.zip.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.*;
import java.nio.channels.FileChannel;
@ -905,7 +904,7 @@ abstract public class GeckoApp
tab.updateTitle(title);
if (tab.getFavicon() == null)
downloadDefaultFavicon(tabId);
tab.downloadFavicon(null);
mMainHandler.post(new Runnable() {
public void run() {
@ -934,73 +933,18 @@ abstract public class GeckoApp
void handleLinkAdded(final int tabId, String rel, final String href) {
if (rel.indexOf("icon") != -1) {
new DownloadFaviconTask(tabId).execute(href);
Tab tab = Tabs.getInstance().getTab(tabId);
if (tab != null)
tab.downloadFavicon(href);
}
}
void downloadDefaultFavicon(final int tabId) {
Tab tab = Tabs.getInstance().getSelectedTab();
if (tab == null)
return;
try {
URL url = new URL(tab.getURL());
String faviconUrl = url.getProtocol() + "://" + url.getAuthority() + "/favicon.ico";
new DownloadFaviconTask(tabId).execute(faviconUrl);
} catch (MalformedURLException e) {
// Optional so not a real error
}
void faviconUpdated(Tab tab) {
if (Tabs.getInstance().isSelectedTab(tab))
mBrowserToolbar.setFavicon(tab.getFavicon());
onTabsChanged();
}
private class DownloadFaviconTask extends AsyncTask<String, Void, Drawable> {
private final int mTabId;
public DownloadFaviconTask(int tabId) {
mTabId = tabId;
}
protected Drawable doInBackground(String... args) {
Drawable image = null;
try {
URL url = new URL(args[0]);
InputStream is = (InputStream) url.getContent();
image = Drawable.createFromStream(is, "src");
} catch (IOException e) {
Log.d(LOG_NAME, "Error loading favicon: " + e);
}
return image;
}
protected void onPostExecute(Drawable image) {
if (image != null) {
Tab tab = Tabs.getInstance().getTab(mTabId);
if (tab == null)
return;
tab.updateFavicon(image);
mMainHandler.post(new Runnable() {
public void run() {
onTabsChanged();
}
});
if (!Tabs.getInstance().isSelectedTab(tab))
return;
final Drawable postImage = image;
mMainHandler.post(new Runnable() {
public void run() {
mBrowserToolbar.setFavicon(postImage);
}
});
}
}
}
void addPluginView(final View view,
final double x, final double y,
final double w, final double h) {

View File

@ -49,6 +49,10 @@ import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.InputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
@ -64,6 +68,7 @@ public class Tab {
private int mHistoryIndex;
private boolean mLoading;
private boolean mBookmark;
private DownloadFaviconTask mFaviconDownloader;
static class HistoryEntry {
public final String mUri;
@ -252,6 +257,55 @@ public class Tab {
}
}
void downloadFavicon(String url) {
if (url == null) {
try {
URL urlObj = new URL(mUrl);
url = urlObj.getProtocol() + "://" + urlObj.getAuthority() + "/favicon.ico";
} catch (MalformedURLException e) {
// Optional so not a real error
return;
}
}
try {
URL urlObj = new URL(url);
// note that the above line may throw a MalformedURLException,
// in which case we abort and don't cancel the old download task.
if (mFaviconDownloader != null) {
mFaviconDownloader.cancel(false);
Log.d(LOG_NAME, "Cancelled old favicon downloader");
}
mFaviconDownloader = new DownloadFaviconTask();
mFaviconDownloader.execute(urlObj);
} catch (MalformedURLException e) {
}
}
private class DownloadFaviconTask extends AsyncTask<URL, Void, Drawable> {
protected Drawable doInBackground(URL... args) {
Drawable image = null;
try {
URL url = args[0];
InputStream is = (InputStream) url.getContent();
image = Drawable.createFromStream(is, "src");
} catch (IOException e) {
Log.d(LOG_NAME, "Error loading favicon: " + e);
}
return image;
}
protected void onPostExecute(Drawable image) {
if (image == null)
return;
updateFavicon(image);
GeckoApp.mAppContext.faviconUpdated(Tab.this);
}
}
private class CheckBookmarkTask extends AsyncTask<Void, Void, Boolean> {
@Override
protected Boolean doInBackground(Void... unused) {