Home | History | Annotate | Download | only in content
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.content;
     18 
     19 import android.accounts.Account;
     20 import android.content.pm.PackageManager;
     21 import android.content.ContentResolver;
     22 import android.os.Bundle;
     23 import android.os.SystemClock;
     24 
     25 /**
     26  * Value type that represents a sync operation.
     27  * @hide
     28  */
     29 public class SyncOperation implements Comparable {
     30     public static final int REASON_BACKGROUND_DATA_SETTINGS_CHANGED = -1;
     31     public static final int REASON_ACCOUNTS_UPDATED = -2;
     32     public static final int REASON_SERVICE_CHANGED = -3;
     33     public static final int REASON_PERIODIC = -4;
     34     public static final int REASON_IS_SYNCABLE = -5;
     35     public static final int REASON_SYNC_AUTO = -6;
     36     public static final int REASON_MASTER_SYNC_AUTO = -7;
     37     public static final int REASON_USER_START = -8;
     38 
     39     private static String[] REASON_NAMES = new String[] {
     40             "DataSettingsChanged",
     41             "AccountsUpdated",
     42             "ServiceChanged",
     43             "Periodic",
     44             "IsSyncable",
     45             "AutoSync",
     46             "MasterSyncAuto",
     47             "UserStart",
     48     };
     49 
     50     public final Account account;
     51     public final int userId;
     52     public final int reason;
     53     public int syncSource;
     54     public String authority;
     55     public final boolean allowParallelSyncs;
     56     public Bundle extras;
     57     public final String key;
     58     public long earliestRunTime;
     59     public boolean expedited;
     60     public SyncStorageEngine.PendingOperation pendingOperation;
     61     public Long backoff;
     62     public long delayUntil;
     63     public long effectiveRunTime;
     64 
     65     public SyncOperation(Account account, int userId, int reason, int source, String authority,
     66             Bundle extras, long delayInMs, long backoff, long delayUntil,
     67             boolean allowParallelSyncs) {
     68         this.account = account;
     69         this.userId = userId;
     70         this.reason = reason;
     71         this.syncSource = source;
     72         this.authority = authority;
     73         this.allowParallelSyncs = allowParallelSyncs;
     74         this.extras = new Bundle(extras);
     75         removeFalseExtra(ContentResolver.SYNC_EXTRAS_UPLOAD);
     76         removeFalseExtra(ContentResolver.SYNC_EXTRAS_MANUAL);
     77         removeFalseExtra(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS);
     78         removeFalseExtra(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
     79         removeFalseExtra(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY);
     80         removeFalseExtra(ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS);
     81         removeFalseExtra(ContentResolver.SYNC_EXTRAS_EXPEDITED);
     82         removeFalseExtra(ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS);
     83         this.delayUntil = delayUntil;
     84         this.backoff = backoff;
     85         final long now = SystemClock.elapsedRealtime();
     86         if (delayInMs < 0) {
     87             this.expedited = true;
     88             this.earliestRunTime = now;
     89         } else {
     90             this.expedited = false;
     91             this.earliestRunTime = now + delayInMs;
     92         }
     93         updateEffectiveRunTime();
     94         this.key = toKey();
     95     }
     96 
     97     private void removeFalseExtra(String extraName) {
     98         if (!extras.getBoolean(extraName, false)) {
     99             extras.remove(extraName);
    100         }
    101     }
    102 
    103     SyncOperation(SyncOperation other) {
    104         this.account = other.account;
    105         this.userId = other.userId;
    106         this.reason = other.reason;
    107         this.syncSource = other.syncSource;
    108         this.authority = other.authority;
    109         this.extras = new Bundle(other.extras);
    110         this.expedited = other.expedited;
    111         this.earliestRunTime = SystemClock.elapsedRealtime();
    112         this.backoff = other.backoff;
    113         this.delayUntil = other.delayUntil;
    114         this.allowParallelSyncs = other.allowParallelSyncs;
    115         this.updateEffectiveRunTime();
    116         this.key = toKey();
    117     }
    118 
    119     public String toString() {
    120         return dump(null, true);
    121     }
    122 
    123     public String dump(PackageManager pm, boolean useOneLine) {
    124         StringBuilder sb = new StringBuilder()
    125                 .append(account.name)
    126                 .append(" u")
    127                 .append(userId).append(" (")
    128                 .append(account.type)
    129                 .append(")")
    130                 .append(", ")
    131                 .append(authority)
    132                 .append(", ")
    133                 .append(SyncStorageEngine.SOURCES[syncSource])
    134                 .append(", earliestRunTime ")
    135                 .append(earliestRunTime);
    136         if (expedited) {
    137             sb.append(", EXPEDITED");
    138         }
    139         sb.append(", reason: ");
    140         sb.append(reasonToString(pm, reason));
    141         if (!useOneLine && !extras.keySet().isEmpty()) {
    142             sb.append("\n    ");
    143             extrasToStringBuilder(extras, sb);
    144         }
    145         return sb.toString();
    146     }
    147 
    148     public static String reasonToString(PackageManager pm, int reason) {
    149         if (reason >= 0) {
    150             if (pm != null) {
    151                 final String[] packages = pm.getPackagesForUid(reason);
    152                 if (packages != null && packages.length == 1) {
    153                     return packages[0];
    154                 }
    155                 final String name = pm.getNameForUid(reason);
    156                 if (name != null) {
    157                     return name;
    158                 }
    159                 return String.valueOf(reason);
    160             } else {
    161                 return String.valueOf(reason);
    162             }
    163         } else {
    164             final int index = -reason - 1;
    165             if (index >= REASON_NAMES.length) {
    166                 return String.valueOf(reason);
    167             } else {
    168                 return REASON_NAMES[index];
    169             }
    170         }
    171     }
    172 
    173     public boolean isInitialization() {
    174         return extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false);
    175     }
    176 
    177     public boolean isExpedited() {
    178         return extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false);
    179     }
    180 
    181     public boolean ignoreBackoff() {
    182         return extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false);
    183     }
    184 
    185     private String toKey() {
    186         StringBuilder sb = new StringBuilder();
    187         sb.append("authority: ").append(authority);
    188         sb.append(" account {name=" + account.name + ", user=" + userId + ", type=" + account.type
    189                 + "}");
    190         sb.append(" extras: ");
    191         extrasToStringBuilder(extras, sb);
    192         return sb.toString();
    193     }
    194 
    195     public static void extrasToStringBuilder(Bundle bundle, StringBuilder sb) {
    196         sb.append("[");
    197         for (String key : bundle.keySet()) {
    198             sb.append(key).append("=").append(bundle.get(key)).append(" ");
    199         }
    200         sb.append("]");
    201     }
    202 
    203     public void updateEffectiveRunTime() {
    204         effectiveRunTime = ignoreBackoff()
    205                 ? earliestRunTime
    206                 : Math.max(
    207                     Math.max(earliestRunTime, delayUntil),
    208                     backoff);
    209     }
    210 
    211     public int compareTo(Object o) {
    212         SyncOperation other = (SyncOperation)o;
    213 
    214         if (expedited != other.expedited) {
    215             return expedited ? -1 : 1;
    216         }
    217 
    218         if (effectiveRunTime == other.effectiveRunTime) {
    219             return 0;
    220         }
    221 
    222         return effectiveRunTime < other.effectiveRunTime ? -1 : 1;
    223     }
    224 }
    225