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

Commit aad2b51b authored by Makoto Onuki's avatar Makoto Onuki
Browse files

Sync too many retries

- When an one-shot sync with app-standby exempt fails too many times in a row,
drop the "exempt from app-standby" flag.

- Also obtain some constants from global settings so we can change them
in CTS.

Bug: 72443754
Test: Manual test (CTS WIP)

Change-Id: Ibdbb348a7ff26a0be04b8f2c256e1f6ead39907d
parent 34ace45e
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -10504,6 +10504,16 @@ public final class Settings {
         */
        public static final String BATTERY_STATS_CONSTANTS = "battery_stats_constants";

        /**
         * SyncManager specific settings.
         *
         * <p>
         * Type: string
         * @hide
         * @see com.android.server.content.SyncManagerConstants
         */
        public static final String SYNC_MANAGER_CONSTANTS = "sync_manager_constants";

        /**
         * Whether or not App Standby feature is enabled. This controls throttling of apps
         * based on usage patterns and predictions.
+1 −0
Original line number Diff line number Diff line
@@ -366,6 +366,7 @@ public class SettingsBackupTest {
                    Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS,
                    Settings.Global.STORAGE_BENCHMARK_INTERVAL,
                    Settings.Global.STORAGE_SETTINGS_CLOBBER_THRESHOLD,
                    Settings.Global.SYNC_MANAGER_CONSTANTS,
                    Settings.Global.SYNC_MAX_RETRY_DELAY_IN_SECONDS,
                    Settings.Global.SYS_FREE_STORAGE_LOG_INTERVAL,
                    Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES,
+10 −5
Original line number Diff line number Diff line
@@ -97,9 +97,7 @@ public final class ContentService extends IContentService.Stub {

        @Override
        public void onBootPhase(int phase) {
            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
                mService.systemReady();
            }
            mService.onBootPhase(phase);
        }


@@ -300,8 +298,15 @@ public final class ContentService extends IContentService.Stub {
                localeFilter, null, null);
    }

    void systemReady() {
    void onBootPhase(int phase) {
        switch (phase) {
            case SystemService.PHASE_SYSTEM_SERVICES_READY:
                getSyncManager();
                break;
        }
        if (mSyncManager != null) {
            mSyncManager.onBootPhase(phase);
        }
    }

    /**
+29 −21
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.job.JobSchedulerInternal;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -102,7 +103,6 @@ import com.android.server.backup.AccountSyncSettingsBackupHelper;
import com.android.server.content.SyncStorageEngine.AuthorityInfo;
import com.android.server.content.SyncStorageEngine.EndPoint;
import com.android.server.content.SyncStorageEngine.OnSyncRequestListener;
import com.android.server.job.JobSchedulerInternal.JobStorePersistStats;

import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -157,18 +157,6 @@ public class SyncManager {
                SystemProperties.getLong("sync.local_sync_delay", 30 * 1000 /* 30 seconds */);
    }

    /**
     * When retrying a sync for the first time use this delay. After that
     * the retry time will double until it reached MAX_SYNC_RETRY_TIME.
     * In milliseconds.
     */
    private static final long INITIAL_SYNC_RETRY_TIME_IN_MS = 30 * 1000; // 30 seconds

    /**
     * Default the max sync retry time to this value.
     */
    private static final long DEFAULT_MAX_SYNC_RETRY_TIME_IN_SECONDS = 60 * 60; // one hour

    /**
     * How long to wait before retrying a sync that failed due to one already being in progress.
     */
@@ -449,6 +437,7 @@ public class SyncManager {
    };

    private final SyncHandler mSyncHandler;
    private final SyncManagerConstants mConstants;

    private volatile boolean mBootCompleted = false;
    private volatile boolean mJobServiceReady = false;
@@ -616,6 +605,7 @@ public class SyncManager {
        }, mSyncHandler);

        mRand = new Random(System.currentTimeMillis());
        mConstants = new SyncManagerConstants(context);

        IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
@@ -756,6 +746,14 @@ public class SyncManager {
        mSyncHandler.post(() -> mLogger.log("onStopUser: user=", userHandle));
    }

    public void onBootPhase(int phase) {
        // Note SyncManager only receives PHASE_SYSTEM_SERVICES_READY and after.
        switch (phase) {
            case SystemService.PHASE_SYSTEM_SERVICES_READY:
                mConstants.start();
                break;
        }
    }

    private void whiteListExistingSyncAdaptersIfNeeded() {
        if (!mSyncStorageEngine.shouldGrantSyncAdaptersAccountAccess()) {
@@ -903,7 +901,10 @@ public class SyncManager {
        }
        if (isLoggable) {
            Log.d(TAG, "one-time sync for: " + requestedAccount + " " + extras.toString() + " "
                    + requestedAuthority);
                    + requestedAuthority
                    + " reason=" + reason
                    + " checkIfAccountReady=" + checkIfAccountReady
                    + " isAppStandbyExempted=" + isAppStandbyExempted);
        }

        AccountAndUser[] accounts = null;
@@ -1368,18 +1369,18 @@ public class SyncManager {
                return;
            }
            // Subsequent delays are the double of the previous delay.
            newDelayInMs = previousSettings.second * 2;
            newDelayInMs =
                    (long) (previousSettings.second * mConstants.getRetryTimeIncreaseFactor());
        }
        if (newDelayInMs <= 0) {
            // The initial delay is the jitterized INITIAL_SYNC_RETRY_TIME_IN_MS.
            newDelayInMs = jitterize(INITIAL_SYNC_RETRY_TIME_IN_MS,
                    (long)(INITIAL_SYNC_RETRY_TIME_IN_MS * 1.1));
            final long initialRetryMs = mConstants.getInitialSyncRetryTimeInSeconds() * 1000;
            newDelayInMs = jitterize(initialRetryMs, (long)(initialRetryMs * 1.1));
        }

        // Cap the delay.
        long maxSyncRetryTimeInSeconds = Settings.Global.getLong(mContext.getContentResolver(),
                Settings.Global.SYNC_MAX_RETRY_DELAY_IN_SECONDS,
                DEFAULT_MAX_SYNC_RETRY_TIME_IN_SECONDS);
        final long maxSyncRetryTimeInSeconds = mConstants.getMaxSyncRetryTimeInSeconds();

        if (newDelayInMs > maxSyncRetryTimeInSeconds * 1000) {
            newDelayInMs = maxSyncRetryTimeInSeconds * 1000;
        }
@@ -1930,6 +1931,7 @@ public class SyncManager {
    protected void dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
        final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
        dumpSyncState(ipw);
        mConstants.dump(pw, "");
        dumpSyncAdapters(ipw);

        if (dumpAll) {
@@ -3573,7 +3575,13 @@ public class SyncManager {
                        reschedulePeriodicSyncH(syncOperation);
                    }
                } else {
                    Log.d(TAG, "failed sync operation " + syncOperation + ", " + syncResult);
                    Log.w(TAG, "failed sync operation " + syncOperation + ", " + syncResult);

                    syncOperation.retries++;
                    if (syncOperation.retries > mConstants.getMaxRetriesWithAppStandbyExemption()) {
                        syncOperation.isAppStandbyExempted = false;
                    }

                    // the operation failed so increase the backoff time
                    increaseBackoffSetting(syncOperation.target);
                    if (!syncOperation.isPeriodic) {
+146 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.server.content;

import android.content.Context;
import android.database.ContentObserver;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.util.KeyValueListParser;
import android.util.Slog;

import java.io.PrintWriter;

public class SyncManagerConstants extends ContentObserver {
    private static final String TAG = "SyncManagerConfig";

    private final Object mLock = new Object();
    private final Context mContext;

    private static final String KEY_INITIAL_SYNC_RETRY_TIME_IN_SECONDS =
            "initial_sync_retry_time_in_seconds";
    private static final int DEF_INITIAL_SYNC_RETRY_TIME_IN_SECONDS = 30;
    private int mInitialSyncRetryTimeInSeconds = DEF_INITIAL_SYNC_RETRY_TIME_IN_SECONDS;

    private static final String KEY_RETRY_TIME_INCREASE_FACTOR =
            "retry_time_increase_factor";
    private static final float DEF_RETRY_TIME_INCREASE_FACTOR = 2.0f;
    private float mRetryTimeIncreaseFactor = DEF_RETRY_TIME_INCREASE_FACTOR;

    private static final String KEY_MAX_SYNC_RETRY_TIME_IN_SECONDS =
            "max_sync_retry_time_in_seconds";
    private static final int DEF_MAX_SYNC_RETRY_TIME_IN_SECONDS = 60 * 60;
    private int mMaxSyncRetryTimeInSeconds = DEF_MAX_SYNC_RETRY_TIME_IN_SECONDS;

    private static final String KEY_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION =
            "max_retries_with_app_standby_exemption";
    private static final int DEF_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION = 5;
    private int mMaxRetriesWithAppStandbyExemption = DEF_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION;

    protected SyncManagerConstants(Context context) {
        super(null);
        mContext = context;
        refresh();
    }

    public void start() {
        mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
                Settings.Global.SYNC_MANAGER_CONSTANTS), false, this);
        refresh();
    }

    @Override
    public void onChange(boolean selfChange) {
        refresh();
    }

    private void refresh() {
        synchronized (mLock) {

            String newValue = Settings.Global.getString(mContext.getContentResolver(),
                    Global.SYNC_MANAGER_CONSTANTS);
            final KeyValueListParser parser = new KeyValueListParser(',');
            try {
                parser.setString(newValue);
            } catch (IllegalArgumentException e) {
                Slog.wtf(TAG, "Bad constants: " + newValue);
            }

            mInitialSyncRetryTimeInSeconds = parser.getInt(
                    KEY_INITIAL_SYNC_RETRY_TIME_IN_SECONDS,
                    DEF_INITIAL_SYNC_RETRY_TIME_IN_SECONDS);

            mMaxSyncRetryTimeInSeconds = parser.getInt(
                    KEY_MAX_SYNC_RETRY_TIME_IN_SECONDS,
                    DEF_MAX_SYNC_RETRY_TIME_IN_SECONDS);

            mRetryTimeIncreaseFactor = parser.getFloat(
                    KEY_RETRY_TIME_INCREASE_FACTOR,
                    DEF_RETRY_TIME_INCREASE_FACTOR);

            mMaxRetriesWithAppStandbyExemption = parser.getInt(
                    KEY_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION,
                    DEF_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION);
        }
    }

    public int getInitialSyncRetryTimeInSeconds() {
        synchronized (mLock) {
            return mInitialSyncRetryTimeInSeconds;
        }
    }

    public float getRetryTimeIncreaseFactor() {
        synchronized (mLock) {
            return mRetryTimeIncreaseFactor;
        }
    }

    public int getMaxSyncRetryTimeInSeconds() {
        synchronized (mLock) {
            return mMaxSyncRetryTimeInSeconds;
        }
    }

    public int getMaxRetriesWithAppStandbyExemption() {
        synchronized (mLock) {
            return mMaxRetriesWithAppStandbyExemption;
        }
    }

    public void dump(PrintWriter pw, String prefix) {
        synchronized (mLock) {
            pw.print(prefix);
            pw.println("SyncManager Config:");

            pw.print(prefix);
            pw.print("  mInitialSyncRetryTimeInSeconds=");
            pw.println(mInitialSyncRetryTimeInSeconds);

            pw.print(prefix);
            pw.print("  mRetryTimeIncreaseFactor=");
            pw.println(mRetryTimeIncreaseFactor);

            pw.print(prefix);
            pw.print("  mMaxSyncRetryTimeInSeconds=");
            pw.println(mMaxSyncRetryTimeInSeconds);

            pw.print(prefix);
            pw.print("  mMaxRetriesWithAppStandbyExemption=");
            pw.println(mMaxRetriesWithAppStandbyExemption);
        }
    }
}
Loading