| package android.os; |
| |
| /** |
| * Describes the source of some work that may be done by someone else. |
| * Currently the public representation of what a work source is is not |
| * defined; this is an opaque container. |
| */ |
| public class WorkSource implements Parcelable { |
| int mNum; |
| int[] mUids; |
| |
| /** |
| * Internal statics to avoid object allocations in some operations. |
| * The WorkSource object itself is not thread safe, but we need to |
| * hold sTmpWorkSource lock while working with these statics. |
| */ |
| static final WorkSource sTmpWorkSource = new WorkSource(0); |
| /** |
| * For returning newbie work from a modification operation. |
| */ |
| static WorkSource sNewbWork; |
| /** |
| * For returning gone work form a modification operation. |
| */ |
| static WorkSource sGoneWork; |
| |
| /** |
| * Create an empty work source. |
| */ |
| public WorkSource() { |
| mNum = 0; |
| } |
| |
| /** |
| * Create a new WorkSource that is a copy of an existing one. |
| * If <var>orig</var> is null, an empty WorkSource is created. |
| */ |
| public WorkSource(WorkSource orig) { |
| if (orig == null) { |
| mNum = 0; |
| return; |
| } |
| mNum = orig.mNum; |
| if (orig.mUids != null) { |
| mUids = orig.mUids.clone(); |
| } else { |
| mUids = null; |
| } |
| } |
| |
| /** @hide */ |
| public WorkSource(int uid) { |
| mNum = 1; |
| mUids = new int[] { uid, 0 }; |
| } |
| |
| WorkSource(Parcel in) { |
| mNum = in.readInt(); |
| mUids = in.createIntArray(); |
| } |
| |
| /** @hide */ |
| public int size() { |
| return mNum; |
| } |
| |
| /** @hide */ |
| public int get(int index) { |
| return mUids[index]; |
| } |
| |
| /** |
| * Clear this WorkSource to be empty. |
| */ |
| public void clear() { |
| mNum = 0; |
| } |
| |
| /** |
| * Compare this WorkSource with another. |
| * @param other The WorkSource to compare against. |
| * @return If there is a difference, true is returned. |
| */ |
| public boolean diff(WorkSource other) { |
| int N = mNum; |
| if (N != other.mNum) { |
| return true; |
| } |
| final int[] uids1 = mUids; |
| final int[] uids2 = other.mUids; |
| for (int i=0; i<N; i++) { |
| if (uids1[i] != uids2[i]) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Replace the current contents of this work source with the given |
| * work source. If <var>other</var> is null, the current work source |
| * will be made empty. |
| */ |
| public void set(WorkSource other) { |
| if (other == null) { |
| mNum = 0; |
| return; |
| } |
| mNum = other.mNum; |
| if (other.mUids != null) { |
| if (mUids != null && mUids.length >= mNum) { |
| System.arraycopy(other.mUids, 0, mUids, 0, mNum); |
| } else { |
| mUids = other.mUids.clone(); |
| } |
| } else { |
| mUids = null; |
| } |
| } |
| |
| /** @hide */ |
| public void set(int uid) { |
| mNum = 1; |
| if (mUids == null) mUids = new int[2]; |
| mUids[0] = uid; |
| } |
| |
| /** @hide */ |
| public WorkSource[] setReturningDiffs(WorkSource other) { |
| synchronized (sTmpWorkSource) { |
| sNewbWork = null; |
| sGoneWork = null; |
| updateLocked(other, true, true); |
| if (sNewbWork != null || sGoneWork != null) { |
| WorkSource[] diffs = new WorkSource[2]; |
| diffs[0] = sNewbWork; |
| diffs[1] = sGoneWork; |
| return diffs; |
| } |
| return null; |
| } |
| } |
| |
| /** |
| * Merge the contents of <var>other</var> WorkSource in to this one. |
| * |
| * @param other The other WorkSource whose contents are to be merged. |
| * @return Returns true if any new sources were added. |
| */ |
| public boolean add(WorkSource other) { |
| synchronized (sTmpWorkSource) { |
| return updateLocked(other, false, false); |
| } |
| } |
| |
| /** @hide */ |
| public WorkSource addReturningNewbs(WorkSource other) { |
| synchronized (sTmpWorkSource) { |
| sNewbWork = null; |
| updateLocked(other, false, true); |
| return sNewbWork; |
| } |
| } |
| |
| /** @hide */ |
| public boolean add(int uid) { |
| synchronized (sTmpWorkSource) { |
| sTmpWorkSource.mUids[0] = uid; |
| return updateLocked(sTmpWorkSource, false, false); |
| } |
| } |
| |
| /** @hide */ |
| public WorkSource addReturningNewbs(int uid) { |
| synchronized (sTmpWorkSource) { |
| sNewbWork = null; |
| sTmpWorkSource.mUids[0] = uid; |
| updateLocked(sTmpWorkSource, false, true); |
| return sNewbWork; |
| } |
| } |
| |
| public boolean remove(WorkSource other) { |
| int N1 = mNum; |
| final int[] uids1 = mUids; |
| final int N2 = other.mNum; |
| final int[] uids2 = other.mUids; |
| boolean changed = false; |
| int i1 = 0; |
| for (int i2=0; i2<N2 && i1<N1; i2++) { |
| if (uids2[i2] == uids1[i1]) { |
| N1--; |
| if (i1 < N1) System.arraycopy(uids1, i1+1, uids1, i1, N1-i1); |
| } |
| while (i1 < N1 && uids2[i2] > uids1[i1]) { |
| i1++; |
| } |
| } |
| |
| mNum = N1; |
| |
| return changed; |
| } |
| |
| private boolean updateLocked(WorkSource other, boolean set, boolean returnNewbs) { |
| int N1 = mNum; |
| int[] uids1 = mUids; |
| final int N2 = other.mNum; |
| final int[] uids2 = other.mUids; |
| boolean changed = false; |
| int i1 = 0; |
| for (int i2=0; i2<N2; i2++) { |
| if (i1 >= N1 || uids2[i2] < uids1[i1]) { |
| // Need to insert a new uid. |
| changed = true; |
| if (uids1 == null) { |
| uids1 = new int[4]; |
| uids1[0] = uids2[i2]; |
| } else if (i1 >= uids1.length) { |
| int[] newuids = new int[(uids1.length*3)/2]; |
| if (i1 > 0) System.arraycopy(uids1, 0, newuids, 0, i1); |
| if (i1 < N1) System.arraycopy(uids1, i1, newuids, i1+1, N1-i1); |
| uids1 = newuids; |
| uids1[i1] = uids2[i2]; |
| } else { |
| if (i1 < N1) System.arraycopy(uids1, i1, uids1, i1+1, N1-i1); |
| uids1[i1] = uids2[i2]; |
| } |
| if (returnNewbs) { |
| if (sNewbWork == null) { |
| sNewbWork = new WorkSource(uids2[i2]); |
| } else { |
| sNewbWork.addLocked(uids2[i2]); |
| } |
| } |
| N1++; |
| i1++; |
| } else { |
| if (!set) { |
| // Skip uids that already exist or are not in 'other'. |
| do { |
| i1++; |
| } while (i1 < N1 && uids2[i2] >= uids1[i1]); |
| } else { |
| // Remove any uids that don't exist in 'other'. |
| int start = i1; |
| while (i1 < N1 && uids2[i2] > uids1[i1]) { |
| if (sGoneWork == null) { |
| sGoneWork = new WorkSource(uids1[i1]); |
| } else { |
| sGoneWork.addLocked(uids1[i1]); |
| } |
| i1++; |
| } |
| if (start < i1) { |
| System.arraycopy(uids1, i1, uids1, start, i1-start); |
| N1 -= i1-start; |
| i1 = start; |
| } |
| // If there is a matching uid, skip it. |
| if (i1 < N1 && uids2[i1] == uids1[i1]) { |
| i1++; |
| } |
| } |
| } |
| } |
| |
| mNum = N1; |
| mUids = uids1; |
| |
| return changed; |
| } |
| |
| private void addLocked(int uid) { |
| if (mUids == null) { |
| mUids = new int[4]; |
| mUids[0] = uid; |
| mNum = 1; |
| return; |
| } |
| if (mNum >= mUids.length) { |
| int[] newuids = new int[(mNum*3)/2]; |
| System.arraycopy(mUids, 0, newuids, 0, mNum); |
| mUids = newuids; |
| } |
| |
| mUids[mNum] = uid; |
| mNum++; |
| } |
| |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| @Override |
| public void writeToParcel(Parcel dest, int flags) { |
| dest.writeInt(mNum); |
| dest.writeIntArray(mUids); |
| } |
| |
| public static final Parcelable.Creator<WorkSource> CREATOR |
| = new Parcelable.Creator<WorkSource>() { |
| public WorkSource createFromParcel(Parcel in) { |
| return new WorkSource(in); |
| } |
| public WorkSource[] newArray(int size) { |
| return new WorkSource[size]; |
| } |
| }; |
| } |