ConcurrentModificationException in SyncManager
updateRunningAccounts and dispatchSyncOperation is running in different thread, and mActiveSyncContexts not synchronization. If methods occur together, mActiveSyncContexts change may occur when cycle is running. Sample: https://code.google.com/p/android/issues/detail?id=195341 Solution: Offboard the traversal from the main thread to the handler thread. Change-Id: Ifb9fbb466a5087186be31f7877c50b8c8b6737e4 Signed-off-by: wangzhengan <wangzglx@gmail.com>
This commit is contained in:
@@ -315,25 +315,9 @@ public class SyncManager {
|
||||
}
|
||||
|
||||
public void updateRunningAccounts() {
|
||||
mRunningAccounts = AccountManagerService.getSingleton().getRunningAccounts();
|
||||
|
||||
if (mBootCompleted) {
|
||||
doDatabaseCleanup();
|
||||
}
|
||||
|
||||
AccountAndUser[] accounts = mRunningAccounts;
|
||||
for (ActiveSyncContext currentSyncContext : mActiveSyncContexts) {
|
||||
if (!containsAccountAndUser(accounts,
|
||||
currentSyncContext.mSyncOperation.target.account,
|
||||
currentSyncContext.mSyncOperation.target.userId)) {
|
||||
Log.d(TAG, "canceling sync since the account is no longer running");
|
||||
sendSyncFinishedOrCanceledMessage(currentSyncContext,
|
||||
null /* no result since this is a cancel */);
|
||||
}
|
||||
}
|
||||
// we must do this since we don't bother scheduling alarms when
|
||||
// the accounts are not set yet
|
||||
sendCheckAlarmsMessage();
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "sending MESSAGE_ACCOUNTS_UPDATED");
|
||||
// Update accounts in handler thread.
|
||||
mSyncHandler.sendEmptyMessage(SyncHandler.MESSAGE_ACCOUNTS_UPDATED);
|
||||
}
|
||||
|
||||
private void doDatabaseCleanup() {
|
||||
@@ -2098,6 +2082,7 @@ public class SyncManager {
|
||||
* obj: {@link com.android.server.content.SyncManager.ActiveSyncContext}
|
||||
*/
|
||||
private static final int MESSAGE_MONITOR_SYNC = 8;
|
||||
private static final int MESSAGE_ACCOUNTS_UPDATED = 9;
|
||||
|
||||
public final SyncNotificationInfo mSyncNotificationInfo = new SyncNotificationInfo();
|
||||
private Long mAlarmScheduleTime = null;
|
||||
@@ -2215,6 +2200,13 @@ public class SyncManager {
|
||||
// to also take into account the periodic syncs.
|
||||
earliestFuturePollTime = scheduleReadyPeriodicSyncs();
|
||||
switch (msg.what) {
|
||||
case SyncHandler.MESSAGE_ACCOUNTS_UPDATED:
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "handleSyncHandlerMessage: MESSAGE_ACCOUNTS_UPDATED");
|
||||
}
|
||||
updateRunningAccountsH();
|
||||
break;
|
||||
|
||||
case SyncHandler.MESSAGE_CANCEL:
|
||||
SyncStorageEngine.EndPoint endpoint = (SyncStorageEngine.EndPoint) msg.obj;
|
||||
Bundle extras = msg.peekData();
|
||||
@@ -2763,6 +2755,28 @@ public class SyncManager {
|
||||
return nextReadyToRunTime;
|
||||
}
|
||||
|
||||
private void updateRunningAccountsH() {
|
||||
mRunningAccounts = AccountManagerService.getSingleton().getRunningAccounts();
|
||||
|
||||
if (mBootCompleted) {
|
||||
doDatabaseCleanup();
|
||||
}
|
||||
|
||||
AccountAndUser[] accounts = mRunningAccounts;
|
||||
for (ActiveSyncContext currentSyncContext : mActiveSyncContexts) {
|
||||
if (!containsAccountAndUser(accounts,
|
||||
currentSyncContext.mSyncOperation.target.account,
|
||||
currentSyncContext.mSyncOperation.target.userId)) {
|
||||
Log.d(TAG, "canceling sync since the account is no longer running");
|
||||
sendSyncFinishedOrCanceledMessage(currentSyncContext,
|
||||
null /* no result since this is a cancel */);
|
||||
}
|
||||
}
|
||||
// we must do this since we don't bother scheduling alarms when
|
||||
// the accounts are not set yet
|
||||
sendCheckAlarmsMessage();
|
||||
}
|
||||
|
||||
private boolean isSyncNotUsingNetworkH(ActiveSyncContext activeSyncContext) {
|
||||
final long bytesTransferredCurrent =
|
||||
getTotalBytesTransferredByUid(activeSyncContext.mSyncAdapterUid);
|
||||
|
||||
Reference in New Issue
Block a user