Resolving race condition while writing recent taskids
There was a race condition, due to which, by the time TaskPersister started writing the taskids to the file, the user was stopped and its data from memory was unloaded, resulting in a NullPointerException Bug: 30944155 Change-Id: Iac3333b7744241c90a7769686983e3f16e6880c1
This commit is contained in:
@@ -87,6 +87,8 @@ public class TaskPersister {
|
|||||||
private final RecentTasks mRecentTasks;
|
private final RecentTasks mRecentTasks;
|
||||||
private final SparseArray<SparseBooleanArray> mTaskIdsInFile = new SparseArray<>();
|
private final SparseArray<SparseBooleanArray> mTaskIdsInFile = new SparseArray<>();
|
||||||
private final File mTaskIdsDir;
|
private final File mTaskIdsDir;
|
||||||
|
// To lock file operations in TaskPersister
|
||||||
|
private final Object mIoLock = new Object();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Value determines write delay mode as follows: < 0 We are Flushing. No delays between writes
|
* Value determines write delay mode as follows: < 0 We are Flushing. No delays between writes
|
||||||
@@ -195,6 +197,7 @@ public class TaskPersister {
|
|||||||
return mTaskIdsInFile.get(userId).clone();
|
return mTaskIdsInFile.get(userId).clone();
|
||||||
}
|
}
|
||||||
final SparseBooleanArray persistedTaskIds = new SparseBooleanArray();
|
final SparseBooleanArray persistedTaskIds = new SparseBooleanArray();
|
||||||
|
synchronized (mIoLock) {
|
||||||
BufferedReader reader = null;
|
BufferedReader reader = null;
|
||||||
String line;
|
String line;
|
||||||
try {
|
try {
|
||||||
@@ -212,20 +215,19 @@ public class TaskPersister {
|
|||||||
} finally {
|
} finally {
|
||||||
IoUtils.closeQuietly(reader);
|
IoUtils.closeQuietly(reader);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
mTaskIdsInFile.put(userId, persistedTaskIds);
|
mTaskIdsInFile.put(userId, persistedTaskIds);
|
||||||
return persistedTaskIds.clone();
|
return persistedTaskIds.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void maybeWritePersistedTaskIdsForUser(@NonNull SparseBooleanArray taskIds, int userId) {
|
void writePersistedTaskIdsForUser(@NonNull SparseBooleanArray taskIds, int userId) {
|
||||||
if (userId < 0) {
|
if (userId < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId);
|
|
||||||
if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIds)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final File persistedTaskIdsFile = getUserPersistedTaskIdsFile(userId);
|
final File persistedTaskIdsFile = getUserPersistedTaskIdsFile(userId);
|
||||||
|
synchronized (mIoLock) {
|
||||||
BufferedWriter writer = null;
|
BufferedWriter writer = null;
|
||||||
try {
|
try {
|
||||||
writer = new BufferedWriter(new FileWriter(persistedTaskIdsFile));
|
writer = new BufferedWriter(new FileWriter(persistedTaskIdsFile));
|
||||||
@@ -240,7 +242,7 @@ public class TaskPersister {
|
|||||||
} finally {
|
} finally {
|
||||||
IoUtils.closeQuietly(writer);
|
IoUtils.closeQuietly(writer);
|
||||||
}
|
}
|
||||||
mTaskIdsInFile.put(userId, taskIds.clone());
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void unloadUserDataFromMemory(int userId) {
|
void unloadUserDataFromMemory(int userId) {
|
||||||
@@ -543,16 +545,23 @@ public class TaskPersister {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void writeTaskIdsFiles() {
|
private void writeTaskIdsFiles() {
|
||||||
int candidateUserIds[];
|
SparseArray<SparseBooleanArray> changedTaskIdsPerUser = new SparseArray<>();
|
||||||
synchronized (mService) {
|
synchronized (mService) {
|
||||||
candidateUserIds = mRecentTasks.usersWithRecentsLoadedLocked();
|
for (int userId : mRecentTasks.usersWithRecentsLoadedLocked()) {
|
||||||
|
SparseBooleanArray taskIdsToSave = mRecentTasks.mPersistedTaskIds.get(userId);
|
||||||
|
SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId);
|
||||||
|
if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIdsToSave)) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
SparseBooleanArray taskIdsToSaveCopy = taskIdsToSave.clone();
|
||||||
|
mTaskIdsInFile.put(userId, taskIdsToSaveCopy);
|
||||||
|
changedTaskIdsPerUser.put(userId, taskIdsToSaveCopy);
|
||||||
}
|
}
|
||||||
SparseBooleanArray taskIdsToSave;
|
|
||||||
for (int userId : candidateUserIds) {
|
|
||||||
synchronized (mService) {
|
|
||||||
taskIdsToSave = mRecentTasks.mPersistedTaskIds.get(userId).clone();
|
|
||||||
}
|
}
|
||||||
maybeWritePersistedTaskIdsForUser(taskIdsToSave, userId);
|
}
|
||||||
|
for (int i = 0; i < changedTaskIdsPerUser.size(); i++) {
|
||||||
|
writePersistedTaskIdsForUser(changedTaskIdsPerUser.valueAt(i),
|
||||||
|
changedTaskIdsPerUser.keyAt(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public class TaskPersisterTest extends AndroidTestCase {
|
|||||||
for (int i = 0; i < 100; i++) {
|
for (int i = 0; i < 100; i++) {
|
||||||
taskIdsOnFile.put(getRandomTaskIdForUser(testUserId), true);
|
taskIdsOnFile.put(getRandomTaskIdForUser(testUserId), true);
|
||||||
}
|
}
|
||||||
mTaskPersister.maybeWritePersistedTaskIdsForUser(taskIdsOnFile, testUserId);
|
mTaskPersister.writePersistedTaskIdsForUser(taskIdsOnFile, testUserId);
|
||||||
SparseBooleanArray newTaskIdsOnFile = mTaskPersister
|
SparseBooleanArray newTaskIdsOnFile = mTaskPersister
|
||||||
.loadPersistedTaskIdsForUser(testUserId);
|
.loadPersistedTaskIdsForUser(testUserId);
|
||||||
assertTrue("TaskIds written differ from TaskIds read back from file",
|
assertTrue("TaskIds written differ from TaskIds read back from file",
|
||||||
|
|||||||
Reference in New Issue
Block a user