Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c2e4691d authored by Fred Quintana's avatar Fred Quintana
Browse files

- make the SyncManager add periodic syncs when it upgrades from a

  version of the accounts.xml file that pre-dated periodic syncs,
  e.g. eclair or early froyo. http://b/2515823
- make the AccountManagerService dump() use a getAccounts call that
  doesn't check the GET_ACCOUNTS permission to make it useful
  in "adb bugreport"
- add some logging to SyncManager to help track down a problem

Change-Id: Icb646909074e2d327d71f6bb39cf06b6fac29e77
parent 74d48436
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1699,7 +1699,7 @@ public class AccountManagerService
                }
            }
        } else {
            Account[] accounts = getAccounts(null /* type */);
            Account[] accounts = getAccountsByType(null /* type */);
            fout.println("Accounts: " + accounts.length);
            for (Account account : accounts) {
                fout.println("  " + account);
+10 −3
Original line number Diff line number Diff line
@@ -416,6 +416,9 @@ public class SyncManager implements OnAccountsUpdateListener {
    }

    private void initializeSyncAdapter(Account account, String authority) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "initializeSyncAdapter: " + account + ", authority " + authority);
        }
        SyncAdapterType syncAdapterType = SyncAdapterType.newKey(authority, account.type);
        RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
                mSyncAdapters.getServiceInfo(syncAdapterType);
@@ -427,9 +430,11 @@ public class SyncManager implements OnAccountsUpdateListener {
        Intent intent = new Intent();
        intent.setAction("android.content.SyncAdapter");
        intent.setComponent(syncAdapterInfo.componentName);
        mContext.bindService(intent, new InitializerServiceConnection(account, authority, mContext,
        if (!mContext.bindService(intent, new InitializerServiceConnection(account, authority, mContext,
                mMainHandler),
                Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND);
                Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND)) {
            Log.w(TAG, "initializeSyncAdapter: failed to bind to " + intent);
        }
    }

    private static class InitializerServiceConnection implements ServiceConnection {
@@ -452,6 +457,9 @@ public class SyncManager implements OnAccountsUpdateListener {
            try {
                if (!mInitialized) {
                    mInitialized = true;
                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
                        Log.v(TAG, "calling initialize: " + mAccount + ", authority " + mAuthority);
                    }
                    ISyncAdapter.Stub.asInterface(service).initialize(mAccount, mAuthority);
                }
            } catch (RemoteException e) {
@@ -1307,7 +1315,6 @@ public class SyncManager implements OnAccountsUpdateListener {
        // it if sync is still failing
        private boolean mErrorNotificationInstalled = false;
        private volatile CountDownLatch mReadyToRunLatch = new CountDownLatch(1);

        public void onBootCompleted() {
            mBootCompleted = true;
            if (mReadyToRunLatch != null) {
+33 −5
Original line number Diff line number Diff line
@@ -121,6 +121,9 @@ public class SyncStorageEngine extends Handler {

    private static final boolean SYNC_ENABLED_DEFAULT = false;

    // the version of the accounts xml file format
    private static final int ACCOUNTS_VERSION = 1;

    public static class PendingOperation {
        final Account account;
        final int syncSource;
@@ -1322,6 +1325,7 @@ public class SyncStorageEngine extends Handler {
     * Read all account information back in to the initial engine state.
     */
    private void readAccountInfoLocked() {
        boolean writeNeeded = false;
        FileInputStream fis = null;
        try {
            fis = mAccountInfoFile.openRead();
@@ -1336,6 +1340,16 @@ public class SyncStorageEngine extends Handler {
            if ("accounts".equals(tagName)) {
                String listen = parser.getAttributeValue(
                        null, "listen-for-tickles");
                String versionString = parser.getAttributeValue(null, "version");
                int version;
                try {
                    version = (versionString == null) ? 0 : Integer.parseInt(versionString);
                } catch (NumberFormatException e) {
                    version = 0;
                }
                if (version < ACCOUNTS_VERSION) {
                    writeNeeded = true;
                }
                mMasterSyncAutomatically = listen == null
                            || Boolean.parseBoolean(listen);
                eventType = parser.next();
@@ -1346,7 +1360,7 @@ public class SyncStorageEngine extends Handler {
                        tagName = parser.getName();
                        if (parser.getDepth() == 2) {
                            if ("authority".equals(tagName)) {
                                authority = parseAuthority(parser);
                                authority = parseAuthority(parser, version);
                                periodicSync = null;
                            }
                        } else if (parser.getDepth() == 3) {
@@ -1364,9 +1378,11 @@ public class SyncStorageEngine extends Handler {
            }
        } catch (XmlPullParserException e) {
            Log.w(TAG, "Error reading accounts", e);
            return;
        } catch (java.io.IOException e) {
            if (fis == null) Log.i(TAG, "No initial accounts");
            else Log.w(TAG, "Error reading accounts", e);
            return;
        } finally {
            if (fis != null) {
                try {
@@ -1375,9 +1391,13 @@ public class SyncStorageEngine extends Handler {
                }
            }
        }

        if (writeNeeded) {
            writeAccountInfoLocked();
        }
    }

    private AuthorityInfo parseAuthority(XmlPullParser parser) {
    private AuthorityInfo parseAuthority(XmlPullParser parser, int version) {
        AuthorityInfo authority = null;
        int id = -1;
        try {
@@ -1406,9 +1426,15 @@ public class SyncStorageEngine extends Handler {
                if (DEBUG_FILE) Log.v(TAG, "Creating entry");
                authority = getOrCreateAuthorityLocked(
                        new Account(accountName, accountType), authorityName, id, false);
                // clear this since we will read these later on
                // If the version is 0 then we are upgrading from a file format that did not
                // know about periodic syncs. In that case don't clear the list since we
                // want the default, which is a daily periodioc sync.
                // Otherwise clear out this default list since we will populate it later with
                // the periodic sync descriptions that are read from the configuration file.
                if (version > 0) {
                    authority.periodicSyncs.clear();
                }
            }
            if (authority != null) {
                authority.enabled = enabled == null || Boolean.parseBoolean(enabled);
                if ("unknown".equals(syncable)) {
@@ -1443,6 +1469,7 @@ public class SyncStorageEngine extends Handler {
        }
        final Pair<Bundle, Long> periodicSync = Pair.create(extras, period);
        authority.periodicSyncs.add(periodicSync);

        return periodicSync;
    }

@@ -1491,6 +1518,7 @@ public class SyncStorageEngine extends Handler {
            out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);

            out.startTag(null, "accounts");
            out.attribute(null, "version", Integer.toString(ACCOUNTS_VERSION));
            if (!mMasterSyncAutomatically) {
                out.attribute(null, "listen-for-tickles", "false");
            }
+106 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.content;

import com.android.internal.os.AtomicFile;

import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;
import android.test.suitebuilder.annotation.SmallTest;
@@ -26,6 +28,7 @@ import android.os.Bundle;

import java.util.List;
import java.io.File;
import java.io.FileOutputStream;

public class SyncStorageEngineTest extends AndroidTestCase {

@@ -193,6 +196,109 @@ public class SyncStorageEngineTest extends AndroidTestCase {
        assertEquals(1, engine.getIsSyncable(account1, authority2));
        assertEquals(0, engine.getIsSyncable(account2, authority2));
    }

    @SmallTest
    public void testAuthorityParsing() throws Exception {
        final Account account = new Account("account1", "type1");
        final String authority1 = "auth1";
        final String authority2 = "auth2";
        final String authority3 = "auth3";
        final Bundle extras = new Bundle();
        PeriodicSync sync1 = new PeriodicSync(account, authority1, extras, (long) (60 * 60 * 24));
        PeriodicSync sync2 = new PeriodicSync(account, authority2, extras, (long) (60 * 60 * 24));
        PeriodicSync sync3 = new PeriodicSync(account, authority3, extras, (long) (60 * 60 * 24));
        PeriodicSync sync1s = new PeriodicSync(account, authority1, extras, 1000);
        PeriodicSync sync2s = new PeriodicSync(account, authority2, extras, 1000);
        PeriodicSync sync3s = new PeriodicSync(account, authority3, extras, 1000);

        MockContentResolver mockResolver = new MockContentResolver();

        final TestContext testContext = new TestContext(mockResolver, getContext());
        SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);

        byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
                + "<accounts>\n"
                + "<authority id=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n"
                + "<authority id=\"1\" account=\"account1\" type=\"type1\" authority=\"auth2\" />\n"
                + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\" />\n"
                + "</accounts>\n").getBytes();

        File syncDir = new File(new File(testContext.getFilesDir(), "system"), "sync");
        syncDir.mkdirs();
        AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
        FileOutputStream fos = accountInfoFile.startWrite();
        fos.write(accountsFileData);
        accountInfoFile.finishWrite(fos);

        engine.clearAndReadState();

        List<PeriodicSync> syncs = engine.getPeriodicSyncs(account, authority1);
        assertEquals(1, syncs.size());
        assertEquals(sync1, syncs.get(0));

        syncs = engine.getPeriodicSyncs(account, authority2);
        assertEquals(1, syncs.size());
        assertEquals(sync2, syncs.get(0));

        syncs = engine.getPeriodicSyncs(account, authority3);
        assertEquals(1, syncs.size());
        assertEquals(sync3, syncs.get(0));

        accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
                + "<accounts version=\"1\">\n"
                + "<authority id=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n"
                + "<authority id=\"1\" account=\"account1\" type=\"type1\" authority=\"auth2\" />\n"
                + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\" />\n"
                + "</accounts>\n").getBytes();

        accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
        fos = accountInfoFile.startWrite();
        fos.write(accountsFileData);
        accountInfoFile.finishWrite(fos);

        engine.clearAndReadState();

        syncs = engine.getPeriodicSyncs(account, authority1);
        assertEquals(0, syncs.size());

        syncs = engine.getPeriodicSyncs(account, authority2);
        assertEquals(0, syncs.size());

        syncs = engine.getPeriodicSyncs(account, authority3);
        assertEquals(0, syncs.size());

        accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
                + "<accounts version=\"1\">\n"
                + "<authority id=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\">\n"
                + "<periodicSync period=\"1000\" />\n"
                + "</authority>"
                + "<authority id=\"1\" account=\"account1\" type=\"type1\" authority=\"auth2\">\n"
                + "<periodicSync period=\"1000\" />\n"
                + "</authority>"
                + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\">\n"
                + "<periodicSync period=\"1000\" />\n"
                + "</authority>"
                + "</accounts>\n").getBytes();

        accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
        fos = accountInfoFile.startWrite();
        fos.write(accountsFileData);
        accountInfoFile.finishWrite(fos);

        engine.clearAndReadState();

        syncs = engine.getPeriodicSyncs(account, authority1);
        assertEquals(1, syncs.size());
        assertEquals(sync1s, syncs.get(0));

        syncs = engine.getPeriodicSyncs(account, authority2);
        assertEquals(1, syncs.size());
        assertEquals(sync2s, syncs.get(0));

        syncs = engine.getPeriodicSyncs(account, authority3);
        assertEquals(1, syncs.size());
        assertEquals(sync3s, syncs.get(0));
    }
}

class TestContext extends ContextWrapper {