1 package 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 */ 8 public 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 /** 80 * Compare this WorkSource with another. 81 * @param other The WorkSource to compare against. 82 * @return If there is a difference, true is returned. 83 */ 84 public boolean diff(WorkSource other) { 85 int N = mNum; 86 if (N != other.mNum) { 87 return true; 88 } 89 final int[] uids1 = mUids; 90 final int[] uids2 = other.mUids; 91 for (int i=0; i<N; i++) { 92 if (uids1[i] != uids2[i]) { 93 return true; 94 } 95 } 96 return false; 97 } 98 99 /** 100 * Replace the current contents of this work source with the given 101 * work source. If <var>other</var> is null, the current work source 102 * will be made empty. 103 */ 104 public void set(WorkSource other) { 105 if (other == null) { 106 mNum = 0; 107 return; 108 } 109 mNum = other.mNum; 110 if (other.mUids != null) { 111 if (mUids != null && mUids.length >= mNum) { 112 System.arraycopy(other.mUids, 0, mUids, 0, mNum); 113 } else { 114 mUids = other.mUids.clone(); 115 } 116 } else { 117 mUids = null; 118 } 119 } 120 121 /** @hide */ 122 public void set(int uid) { 123 mNum = 1; 124 if (mUids == null) mUids = new int[2]; 125 mUids[0] = uid; 126 } 127 128 /** @hide */ 129 public WorkSource[] setReturningDiffs(WorkSource other) { 130 synchronized (sTmpWorkSource) { 131 sNewbWork = null; 132 sGoneWork = null; 133 updateLocked(other, true, true); 134 if (sNewbWork != null || sGoneWork != null) { 135 WorkSource[] diffs = new WorkSource[2]; 136 diffs[0] = sNewbWork; 137 diffs[1] = sGoneWork; 138 return diffs; 139 } 140 return null; 141 } 142 } 143 144 /** 145 * Merge the contents of <var>other</var> WorkSource in to this one. 146 * 147 * @param other The other WorkSource whose contents are to be merged. 148 * @return Returns true if any new sources were added. 149 */ 150 public boolean add(WorkSource other) { 151 synchronized (sTmpWorkSource) { 152 return updateLocked(other, false, false); 153 } 154 } 155 156 /** @hide */ 157 public WorkSource addReturningNewbs(WorkSource other) { 158 synchronized (sTmpWorkSource) { 159 sNewbWork = null; 160 updateLocked(other, false, true); 161 return sNewbWork; 162 } 163 } 164 165 /** @hide */ 166 public boolean add(int uid) { 167 synchronized (sTmpWorkSource) { 168 sTmpWorkSource.mUids[0] = uid; 169 return updateLocked(sTmpWorkSource, false, false); 170 } 171 } 172 173 /** @hide */ 174 public WorkSource addReturningNewbs(int uid) { 175 synchronized (sTmpWorkSource) { 176 sNewbWork = null; 177 sTmpWorkSource.mUids[0] = uid; 178 updateLocked(sTmpWorkSource, false, true); 179 return sNewbWork; 180 } 181 } 182 183 public boolean remove(WorkSource other) { 184 int N1 = mNum; 185 final int[] uids1 = mUids; 186 final int N2 = other.mNum; 187 final int[] uids2 = other.mUids; 188 boolean changed = false; 189 int i1 = 0; 190 for (int i2=0; i2<N2 && i1<N1; i2++) { 191 if (uids2[i2] == uids1[i1]) { 192 N1--; 193 if (i1 < N1) System.arraycopy(uids1, i1+1, uids1, i1, N1-i1); 194 } 195 while (i1 < N1 && uids2[i2] > uids1[i1]) { 196 i1++; 197 } 198 } 199 200 mNum = N1; 201 202 return changed; 203 } 204 205 private boolean updateLocked(WorkSource other, boolean set, boolean returnNewbs) { 206 int N1 = mNum; 207 int[] uids1 = mUids; 208 final int N2 = other.mNum; 209 final int[] uids2 = other.mUids; 210 boolean changed = false; 211 int i1 = 0; 212 for (int i2=0; i2<N2; i2++) { 213 if (i1 >= N1 || uids2[i2] < uids1[i1]) { 214 // Need to insert a new uid. 215 changed = true; 216 if (uids1 == null) { 217 uids1 = new int[4]; 218 uids1[0] = uids2[i2]; 219 } else if (i1 >= uids1.length) { 220 int[] newuids = new int[(uids1.length*3)/2]; 221 if (i1 > 0) System.arraycopy(uids1, 0, newuids, 0, i1); 222 if (i1 < N1) System.arraycopy(uids1, i1, newuids, i1+1, N1-i1); 223 uids1 = newuids; 224 uids1[i1] = uids2[i2]; 225 } else { 226 if (i1 < N1) System.arraycopy(uids1, i1, uids1, i1+1, N1-i1); 227 uids1[i1] = uids2[i2]; 228 } 229 if (returnNewbs) { 230 if (sNewbWork == null) { 231 sNewbWork = new WorkSource(uids2[i2]); 232 } else { 233 sNewbWork.addLocked(uids2[i2]); 234 } 235 } 236 N1++; 237 i1++; 238 } else { 239 if (!set) { 240 // Skip uids that already exist or are not in 'other'. 241 do { 242 i1++; 243 } while (i1 < N1 && uids2[i2] >= uids1[i1]); 244 } else { 245 // Remove any uids that don't exist in 'other'. 246 int start = i1; 247 while (i1 < N1 && uids2[i2] > uids1[i1]) { 248 if (sGoneWork == null) { 249 sGoneWork = new WorkSource(uids1[i1]); 250 } else { 251 sGoneWork.addLocked(uids1[i1]); 252 } 253 i1++; 254 } 255 if (start < i1) { 256 System.arraycopy(uids1, i1, uids1, start, i1-start); 257 N1 -= i1-start; 258 i1 = start; 259 } 260 // If there is a matching uid, skip it. 261 if (i1 < N1 && uids2[i1] == uids1[i1]) { 262 i1++; 263 } 264 } 265 } 266 } 267 268 mNum = N1; 269 mUids = uids1; 270 271 return changed; 272 } 273 274 private void addLocked(int uid) { 275 if (mUids == null) { 276 mUids = new int[4]; 277 mUids[0] = uid; 278 mNum = 1; 279 return; 280 } 281 if (mNum >= mUids.length) { 282 int[] newuids = new int[(mNum*3)/2]; 283 System.arraycopy(mUids, 0, newuids, 0, mNum); 284 mUids = newuids; 285 } 286 287 mUids[mNum] = uid; 288 mNum++; 289 } 290 291 @Override 292 public int describeContents() { 293 return 0; 294 } 295 296 @Override 297 public void writeToParcel(Parcel dest, int flags) { 298 dest.writeInt(mNum); 299 dest.writeIntArray(mUids); 300 } 301 302 public static final Parcelable.Creator<WorkSource> CREATOR 303 = new Parcelable.Creator<WorkSource>() { 304 public WorkSource createFromParcel(Parcel in) { 305 return new WorkSource(in); 306 } 307 public WorkSource[] newArray(int size) { 308 return new WorkSource[size]; 309 } 310 }; 311 } 312