Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ private TrackerBlocklist(Context c) {
* @return The current instance of the TrackerBlocklist, if none, a new instance
* is created.
*/
public static TrackerBlocklist getInstance(Context c) {
// Called from both native packet threads and UI threads.
public static synchronized TrackerBlocklist getInstance(Context c) {
if (instance == null)
instance = new TrackerBlocklist(c);

Expand All @@ -85,7 +86,7 @@ public static String getBlockingKey(Tracker t) {
*
* @param c Context
*/
public void loadSettings(Context c) {
public synchronized void loadSettings(Context c) {
SharedPreferences prefs = c.getSharedPreferences(PREF_BLOCKLIST, Context.MODE_PRIVATE);
Set<String> set = prefs.getStringSet(SHARED_PREFS_BLOCKLIST_APPS_KEY, null);
PackageUidResolver resolver = new PackageUidResolver() {
Expand Down Expand Up @@ -226,14 +227,14 @@ public Set<Integer> getBlocklist() {
* @param uid Uid of the app
* @return Information about what specific trackers are blocked
*/
public Set<String> getSubset(int uid) {
public synchronized Set<String> getSubset(int uid) {
return blockmap.get(uid);
}

/**
* Completely clear blocklist.
*/
public void clear() {
public synchronized void clear() {
blockmap.clear();
}

Expand All @@ -242,7 +243,7 @@ public void clear() {
*
* @param uid Uid of app
*/
public void clear(int uid) {
public synchronized void clear(int uid) {
blockmap.remove(uid);
}

Expand Down Expand Up @@ -303,7 +304,7 @@ public synchronized void unblock(int uid, Tracker t) {
* @param key Key of the tracker
* @return Whether access to this tracker is blocked
*/
public boolean blocked(int uid, String key) {
public synchronized boolean blocked(int uid, String key) {
Set<String> trackers = this.getSubset(uid);
if (trackers == null) {
return true;
Expand All @@ -319,7 +320,7 @@ public boolean blocked(int uid, String key) {
* @param t Tracker
* @return Whether access to this tracker is blocked
*/
public boolean blockedTracker(int uid, Tracker t) {
public synchronized boolean blockedTracker(int uid, Tracker t) {
return blocked(uid, t.category)
&& blocked(uid, getBlockingKey(t));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
import org.junit.Before;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class TrackerBlocklistTest {
private static final int UID = 1001;

Expand Down Expand Up @@ -202,4 +206,45 @@ public void blockedTrackerRequiresBothCategoryAndKeyBlocked() {
blocklist.block(UID, tracker);
assertTrue(blocklist.blockedTracker(UID, tracker));
}

@Test
public void concurrentReadersAndWritersDoNotThrow() throws Exception {
TrackerBlocklist blocklist = TrackerBlocklist.getInstance(null);
int uidCount = 8;
for (int uid = 0; uid < uidCount; uid++)
blocklist.ensureDefaults(uid, false);

final int iterations = 1000;
List<Throwable> errors = Collections.synchronizedList(new ArrayList<>());

Runnable writer = () -> {
try {
for (int i = 0; i < iterations; i++) {
blocklist.applyStrictModeToAll(i % 2 == 0);
blocklist.unblock(0, "Advertising | Writer");
blocklist.block(0, "Advertising | Writer");
}
} catch (Throwable t) {
errors.add(t);
}
};
Runnable reader = () -> {
try {
for (int i = 0; i < iterations; i++)
for (int uid = 0; uid < uidCount; uid++)
blocklist.blocked(uid, "Content");
} catch (Throwable t) {
errors.add(t);
}
};

Thread[] threads = {new Thread(writer), new Thread(writer),
new Thread(reader), new Thread(reader)};
for (Thread thread : threads)
thread.start();
for (Thread thread : threads)
thread.join(30000);

assertTrue(errors.toString(), errors.isEmpty());
}
}