WorkSource.java revision 94838913abf6363532cd32b9c795917d808228cc
1package android.os; 2 3/** 4 * Describes the source of some work that may be done by someone else. 5 * Currently the public representation of what a work source is is not 6 * defined; this is an opaque container. 7 */ 8public class WorkSource implements Parcelable { 9 int mNum; 10 int[] mUids; 11 12 /** 13 * Internal statics to avoid object allocations in some operations. 14 * The WorkSource object itself is not thread safe, but we need to 15 * hold sTmpWorkSource lock while working with these statics. 16 */ 17 static final WorkSource sTmpWorkSource = new WorkSource(0); 18 /** 19 * For returning newbie work from a modification operation. 20 */ 21 static WorkSource sNewbWork; 22 /** 23 * For returning gone work form a modification operation. 24 */ 25 static WorkSource sGoneWork; 26 27 /** 28 * Create an empty work source. 29 */ 30 public WorkSource() { 31 mNum = 0; 32 } 33 34 /** 35 * Create a new WorkSource that is a copy of an existing one. 36 * If <var>orig</var> is null, an empty WorkSource is created. 37 */ 38 public WorkSource(WorkSource orig) { 39 if (orig == null) { 40 mNum = 0; 41 return; 42 } 43 mNum = orig.mNum; 44 if (orig.mUids != null) { 45 mUids = orig.mUids.clone(); 46 } else { 47 mUids = null; 48 } 49 } 50 51 /** @hide */ 52 public WorkSource(int uid) { 53 mNum = 1; 54 mUids = new int[] { uid, 0 }; 55 } 56 57 WorkSource(Parcel in) { 58 mNum = in.readInt(); 59 mUids = in.createIntArray(); 60 } 61 62 /** @hide */ 63 public int size() { 64 return mNum; 65 } 66 67 /** @hide */ 68 public int get(int index) { 69 return mUids[index]; 70 } 71 72 /** 73 * Clear this WorkSource to be empty. 74 */ 75 public void clear() { 76 mNum = 0; 77 } 78 79 @Override 80 public boolean equals(Object o) { 81 return o instanceof WorkSource && !diff((WorkSource)o); 82 } 83 84 @Override 85 public int hashCode() { 86 int result = 0; 87 for (int i = 0; i < mNum; i++) { 88 result = ((result << 4) | (result >>> 28)) ^ mUids[i]; 89 } 90 return result; 91 } 92 93 /** 94 * Compare this WorkSource with another. 95 * @param other The WorkSource to compare against. 96 * @return If there is a difference, true is returned. 97 */ 98 public boolean diff(WorkSource other) { 99 int N = mNum; 100 if (N != other.mNum) { 101 return true; 102 } 103 final int[] uids1 = mUids; 104 final int[] uids2 = other.mUids; 105 for (int i=0; i<N; i++) { 106 if (uids1[i] != uids2[i]) { 107 return true; 108 } 109 } 110 return false; 111 } 112 113 /** 114 * Replace the current contents of this work source with the given 115 * work source. If <var>other</var> is null, the current work source 116 * will be made empty. 117 */ 118 public void set(WorkSource other) { 119 if (other == null) { 120 mNum = 0; 121 return; 122 } 123 mNum = other.mNum; 124 if (other.mUids != null) { 125 if (mUids != null && mUids.length >= mNum) { 126 System.arraycopy(other.mUids, 0, mUids, 0, mNum); 127 } else { 128 mUids = other.mUids.clone(); 129 } 130 } else { 131 mUids = null; 132 } 133 } 134 135 /** @hide */ 136 public void set(int uid) { 137 mNum = 1; 138 if (mUids == null) mUids = new int[2]; 139 mUids[0] = uid; 140 } 141 142 /** @hide */ 143 public WorkSource[] setReturningDiffs(WorkSource other) { 144 synchronized (sTmpWorkSource) { 145 sNewbWork = null; 146 sGoneWork = null; 147 updateLocked(other, true, true); 148 if (sNewbWork != null || sGoneWork != null) { 149 WorkSource[] diffs = new WorkSource[2]; 150 diffs[0] = sNewbWork; 151 diffs[1] = sGoneWork; 152 return diffs; 153 } 154 return null; 155 } 156 } 157 158 /** 159 * Merge the contents of <var>other</var> WorkSource in to this one. 160 * 161 * @param other The other WorkSource whose contents are to be merged. 162 * @return Returns true if any new sources were added. 163 */ 164 public boolean add(WorkSource other) { 165 synchronized (sTmpWorkSource) { 166 return updateLocked(other, false, false); 167 } 168 } 169 170 /** @hide */ 171 public WorkSource addReturningNewbs(WorkSource other) { 172 synchronized (sTmpWorkSource) { 173 sNewbWork = null; 174 updateLocked(other, false, true); 175 return sNewbWork; 176 } 177 } 178 179 /** @hide */ 180 public boolean add(int uid) { 181 synchronized (sTmpWorkSource) { 182 sTmpWorkSource.mUids[0] = uid; 183 return updateLocked(sTmpWorkSource, false, false); 184 } 185 } 186 187 /** @hide */ 188 public WorkSource addReturningNewbs(int uid) { 189 synchronized (sTmpWorkSource) { 190 sNewbWork = null; 191 sTmpWorkSource.mUids[0] = uid; 192 updateLocked(sTmpWorkSource, false, true); 193 return sNewbWork; 194 } 195 } 196 197 public boolean remove(WorkSource other) { 198 int N1 = mNum; 199 final int[] uids1 = mUids; 200 final int N2 = other.mNum; 201 final int[] uids2 = other.mUids; 202 boolean changed = false; 203 int i1 = 0; 204 for (int i2=0; i2<N2 && i1<N1; i2++) { 205 if (uids2[i2] == uids1[i1]) { 206 N1--; 207 if (i1 < N1) System.arraycopy(uids1, i1+1, uids1, i1, N1-i1); 208 } 209 while (i1 < N1 && uids2[i2] > uids1[i1]) { 210 i1++; 211 } 212 } 213 214 mNum = N1; 215 216 return changed; 217 } 218 219 private boolean updateLocked(WorkSource other, boolean set, boolean returnNewbs) { 220 int N1 = mNum; 221 int[] uids1 = mUids; 222 final int N2 = other.mNum; 223 final int[] uids2 = other.mUids; 224 boolean changed = false; 225 int i1 = 0; 226 for (int i2=0; i2<N2; i2++) { 227 if (i1 >= N1 || uids2[i2] < uids1[i1]) { 228 // Need to insert a new uid. 229 changed = true; 230 if (uids1 == null) { 231 uids1 = new int[4]; 232 uids1[0] = uids2[i2]; 233 } else if (i1 >= uids1.length) { 234 int[] newuids = new int[(uids1.length*3)/2]; 235 if (i1 > 0) System.arraycopy(uids1, 0, newuids, 0, i1); 236 if (i1 < N1) System.arraycopy(uids1, i1, newuids, i1+1, N1-i1); 237 uids1 = newuids; 238 uids1[i1] = uids2[i2]; 239 } else { 240 if (i1 < N1) System.arraycopy(uids1, i1, uids1, i1+1, N1-i1); 241 uids1[i1] = uids2[i2]; 242 } 243 if (returnNewbs) { 244 if (sNewbWork == null) { 245 sNewbWork = new WorkSource(uids2[i2]); 246 } else { 247 sNewbWork.addLocked(uids2[i2]); 248 } 249 } 250 N1++; 251 i1++; 252 } else { 253 if (!set) { 254 // Skip uids that already exist or are not in 'other'. 255 do { 256 i1++; 257 } while (i1 < N1 && uids2[i2] >= uids1[i1]); 258 } else { 259 // Remove any uids that don't exist in 'other'. 260 int start = i1; 261 while (i1 < N1 && uids2[i2] > uids1[i1]) { 262 if (sGoneWork == null) { 263 sGoneWork = new WorkSource(uids1[i1]); 264 } else { 265 sGoneWork.addLocked(uids1[i1]); 266 } 267 i1++; 268 } 269 if (start < i1) { 270 System.arraycopy(uids1, i1, uids1, start, i1-start); 271 N1 -= i1-start; 272 i1 = start; 273 } 274 // If there is a matching uid, skip it. 275 if (i1 < N1 && uids2[i1] == uids1[i1]) { 276 i1++; 277 } 278 } 279 } 280 } 281 282 mNum = N1; 283 mUids = uids1; 284 285 return changed; 286 } 287 288 private void addLocked(int uid) { 289 if (mUids == null) { 290 mUids = new int[4]; 291 mUids[0] = uid; 292 mNum = 1; 293 return; 294 } 295 if (mNum >= mUids.length) { 296 int[] newuids = new int[(mNum*3)/2]; 297 System.arraycopy(mUids, 0, newuids, 0, mNum); 298 mUids = newuids; 299 } 300 301 mUids[mNum] = uid; 302 mNum++; 303 } 304 305 @Override 306 public int describeContents() { 307 return 0; 308 } 309 310 @Override 311 public void writeToParcel(Parcel dest, int flags) { 312 dest.writeInt(mNum); 313 dest.writeIntArray(mUids); 314 } 315 316 public static final Parcelable.Creator<WorkSource> CREATOR 317 = new Parcelable.Creator<WorkSource>() { 318 public WorkSource createFromParcel(Parcel in) { 319 return new WorkSource(in); 320 } 321 public WorkSource[] newArray(int size) { 322 return new WorkSource[size]; 323 } 324 }; 325} 326