Home | History | Annotate | Download | only in os
      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