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