1 package android.os;
2 
3 import android.os.WorkSourceProto;
4 import android.util.Log;
5 import android.util.proto.ProtoOutputStream;
6 
7 import java.util.Arrays;
8 
9 /**
10  * Describes the source of some work that may be done by someone else.
11  * Currently the public representation of what a work source is is not
12  * defined; this is an opaque container.
13  */
14 public class WorkSource implements Parcelable {
15     static final String TAG = "WorkSource";
16     static final boolean DEBUG = false;
17 
18     int mNum;
19     int[] mUids;
20     String[] mNames;
21 
22     /**
23      * Internal statics to avoid object allocations in some operations.
24      * The WorkSource object itself is not thread safe, but we need to
25      * hold sTmpWorkSource lock while working with these statics.
26      */
27     static final WorkSource sTmpWorkSource = new WorkSource(0);
28     /**
29      * For returning newbie work from a modification operation.
30      */
31     static WorkSource sNewbWork;
32     /**
33      * For returning gone work form a modification operation.
34      */
35     static WorkSource sGoneWork;
36 
37     /**
38      * Create an empty work source.
39      */
WorkSource()40     public WorkSource() {
41         mNum = 0;
42     }
43 
44     /**
45      * Create a new WorkSource that is a copy of an existing one.
46      * If <var>orig</var> is null, an empty WorkSource is created.
47      */
WorkSource(WorkSource orig)48     public WorkSource(WorkSource orig) {
49         if (orig == null) {
50             mNum = 0;
51             return;
52         }
53         mNum = orig.mNum;
54         if (orig.mUids != null) {
55             mUids = orig.mUids.clone();
56             mNames = orig.mNames != null ? orig.mNames.clone() : null;
57         } else {
58             mUids = null;
59             mNames = null;
60         }
61     }
62 
63     /** @hide */
WorkSource(int uid)64     public WorkSource(int uid) {
65         mNum = 1;
66         mUids = new int[] { uid, 0 };
67         mNames = null;
68     }
69 
70     /** @hide */
WorkSource(int uid, String name)71     public WorkSource(int uid, String name) {
72         if (name == null) {
73             throw new NullPointerException("Name can't be null");
74         }
75         mNum = 1;
76         mUids = new int[] { uid, 0 };
77         mNames = new String[] { name, null };
78     }
79 
WorkSource(Parcel in)80     WorkSource(Parcel in) {
81         mNum = in.readInt();
82         mUids = in.createIntArray();
83         mNames = in.createStringArray();
84     }
85 
86     /** @hide */
size()87     public int size() {
88         return mNum;
89     }
90 
91     /** @hide */
get(int index)92     public int get(int index) {
93         return mUids[index];
94     }
95 
96     /** @hide */
getName(int index)97     public String getName(int index) {
98         return mNames != null ? mNames[index] : null;
99     }
100 
101     /**
102      * Clear names from this WorkSource.  Uids are left intact.
103      *
104      * <p>Useful when combining with another WorkSource that doesn't have names.
105      * @hide
106      */
clearNames()107     public void clearNames() {
108         if (mNames != null) {
109             mNames = null;
110             // Clear out any duplicate uids now that we don't have names to disambiguate them.
111             int destIndex = 1;
112             int newNum = mNum;
113             for (int sourceIndex = 1; sourceIndex < mNum; sourceIndex++) {
114                 if (mUids[sourceIndex] == mUids[sourceIndex - 1]) {
115                     newNum--;
116                 } else {
117                     mUids[destIndex] = mUids[sourceIndex];
118                     destIndex++;
119                 }
120             }
121             mNum = newNum;
122         }
123     }
124 
125     /**
126      * Clear this WorkSource to be empty.
127      */
clear()128     public void clear() {
129         mNum = 0;
130     }
131 
132     @Override
equals(Object o)133     public boolean equals(Object o) {
134         return o instanceof WorkSource && !diff((WorkSource)o);
135     }
136 
137     @Override
hashCode()138     public int hashCode() {
139         int result = 0;
140         for (int i = 0; i < mNum; i++) {
141             result = ((result << 4) | (result >>> 28)) ^ mUids[i];
142         }
143         if (mNames != null) {
144             for (int i = 0; i < mNum; i++) {
145                 result = ((result << 4) | (result >>> 28)) ^ mNames[i].hashCode();
146             }
147         }
148         return result;
149     }
150 
151     /**
152      * Compare this WorkSource with another.
153      * @param other The WorkSource to compare against.
154      * @return If there is a difference, true is returned.
155      */
diff(WorkSource other)156     public boolean diff(WorkSource other) {
157         int N = mNum;
158         if (N != other.mNum) {
159             return true;
160         }
161         final int[] uids1 = mUids;
162         final int[] uids2 = other.mUids;
163         final String[] names1 = mNames;
164         final String[] names2 = other.mNames;
165         for (int i=0; i<N; i++) {
166             if (uids1[i] != uids2[i]) {
167                 return true;
168             }
169             if (names1 != null && names2 != null && !names1[i].equals(names2[i])) {
170                 return true;
171             }
172         }
173         return false;
174     }
175 
176     /**
177      * Replace the current contents of this work source with the given
178      * work source.  If <var>other</var> is null, the current work source
179      * will be made empty.
180      */
set(WorkSource other)181     public void set(WorkSource other) {
182         if (other == null) {
183             mNum = 0;
184             return;
185         }
186         mNum = other.mNum;
187         if (other.mUids != null) {
188             if (mUids != null && mUids.length >= mNum) {
189                 System.arraycopy(other.mUids, 0, mUids, 0, mNum);
190             } else {
191                 mUids = other.mUids.clone();
192             }
193             if (other.mNames != null) {
194                 if (mNames != null && mNames.length >= mNum) {
195                     System.arraycopy(other.mNames, 0, mNames, 0, mNum);
196                 } else {
197                     mNames = other.mNames.clone();
198                 }
199             } else {
200                 mNames = null;
201             }
202         } else {
203             mUids = null;
204             mNames = null;
205         }
206     }
207 
208     /** @hide */
set(int uid)209     public void set(int uid) {
210         mNum = 1;
211         if (mUids == null) mUids = new int[2];
212         mUids[0] = uid;
213         mNames = null;
214     }
215 
216     /** @hide */
set(int uid, String name)217     public void set(int uid, String name) {
218         if (name == null) {
219             throw new NullPointerException("Name can't be null");
220         }
221         mNum = 1;
222         if (mUids == null) {
223             mUids = new int[2];
224             mNames = new String[2];
225         }
226         mUids[0] = uid;
227         mNames[0] = name;
228     }
229 
230     /** @hide */
setReturningDiffs(WorkSource other)231     public WorkSource[] setReturningDiffs(WorkSource other) {
232         synchronized (sTmpWorkSource) {
233             sNewbWork = null;
234             sGoneWork = null;
235             updateLocked(other, true, true);
236             if (sNewbWork != null || sGoneWork != null) {
237                 WorkSource[] diffs = new WorkSource[2];
238                 diffs[0] = sNewbWork;
239                 diffs[1] = sGoneWork;
240                 return diffs;
241             }
242             return null;
243         }
244     }
245 
246     /**
247      * Merge the contents of <var>other</var> WorkSource in to this one.
248      *
249      * @param other The other WorkSource whose contents are to be merged.
250      * @return Returns true if any new sources were added.
251      */
add(WorkSource other)252     public boolean add(WorkSource other) {
253         synchronized (sTmpWorkSource) {
254             return updateLocked(other, false, false);
255         }
256     }
257 
258     /** @hide */
addReturningNewbs(WorkSource other)259     public WorkSource addReturningNewbs(WorkSource other) {
260         synchronized (sTmpWorkSource) {
261             sNewbWork = null;
262             updateLocked(other, false, true);
263             return sNewbWork;
264         }
265     }
266 
267     /** @hide */
add(int uid)268     public boolean add(int uid) {
269         if (mNum <= 0) {
270             mNames = null;
271             insert(0, uid);
272             return true;
273         }
274         if (mNames != null) {
275             throw new IllegalArgumentException("Adding without name to named " + this);
276         }
277         int i = Arrays.binarySearch(mUids, 0, mNum, uid);
278         if (DEBUG) Log.d(TAG, "Adding uid " + uid + " to " + this + ": binsearch res = " + i);
279         if (i >= 0) {
280             return false;
281         }
282         insert(-i-1, uid);
283         return true;
284     }
285 
286     /** @hide */
add(int uid, String name)287     public boolean add(int uid, String name) {
288         if (mNum <= 0) {
289             insert(0, uid, name);
290             return true;
291         }
292         if (mNames == null) {
293             throw new IllegalArgumentException("Adding name to unnamed " + this);
294         }
295         int i;
296         for (i=0; i<mNum; i++) {
297             if (mUids[i] > uid) {
298                 break;
299             }
300             if (mUids[i] == uid) {
301                 int diff = mNames[i].compareTo(name);
302                 if (diff > 0) {
303                     break;
304                 }
305                 if (diff == 0) {
306                     return false;
307                 }
308             }
309         }
310         insert(i, uid, name);
311         return true;
312     }
313 
314     /** @hide */
addReturningNewbs(int uid)315     public WorkSource addReturningNewbs(int uid) {
316         synchronized (sTmpWorkSource) {
317             sNewbWork = null;
318             sTmpWorkSource.mUids[0] = uid;
319             updateLocked(sTmpWorkSource, false, true);
320             return sNewbWork;
321         }
322     }
323 
remove(WorkSource other)324     public boolean remove(WorkSource other) {
325         if (mNum <= 0 || other.mNum <= 0) {
326             return false;
327         }
328         if (mNames == null && other.mNames == null) {
329             return removeUids(other);
330         } else {
331             if (mNames == null) {
332                 throw new IllegalArgumentException("Other " + other + " has names, but target "
333                         + this + " does not");
334             }
335             if (other.mNames == null) {
336                 throw new IllegalArgumentException("Target " + this + " has names, but other "
337                         + other + " does not");
338             }
339             return removeUidsAndNames(other);
340         }
341     }
342 
343     /** @hide */
stripNames()344     public WorkSource stripNames() {
345         if (mNum <= 0) {
346             return new WorkSource();
347         }
348         WorkSource result = new WorkSource();
349         int lastUid = -1;
350         for (int i=0; i<mNum; i++) {
351             int uid = mUids[i];
352             if (i == 0 || lastUid != uid) {
353                 result.add(uid);
354             }
355         }
356         return result;
357     }
358 
removeUids(WorkSource other)359     private boolean removeUids(WorkSource other) {
360         int N1 = mNum;
361         final int[] uids1 = mUids;
362         final int N2 = other.mNum;
363         final int[] uids2 = other.mUids;
364         boolean changed = false;
365         int i1 = 0, i2 = 0;
366         if (DEBUG) Log.d(TAG, "Remove " + other + " from " + this);
367         while (i1 < N1 && i2 < N2) {
368             if (DEBUG) Log.d(TAG, "Step: target @ " + i1 + " of " + N1 + ", other @ " + i2
369                     + " of " + N2);
370             if (uids2[i2] == uids1[i1]) {
371                 if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1
372                         + ": remove " + uids1[i1]);
373                 N1--;
374                 changed = true;
375                 if (i1 < N1) System.arraycopy(uids1, i1+1, uids1, i1, N1-i1);
376                 i2++;
377             } else if (uids2[i2] > uids1[i1]) {
378                 if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1 + ": skip i1");
379                 i1++;
380             } else {
381                 if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1 + ": skip i2");
382                 i2++;
383             }
384         }
385 
386         mNum = N1;
387 
388         return changed;
389     }
390 
removeUidsAndNames(WorkSource other)391     private boolean removeUidsAndNames(WorkSource other) {
392         int N1 = mNum;
393         final int[] uids1 = mUids;
394         final String[] names1 = mNames;
395         final int N2 = other.mNum;
396         final int[] uids2 = other.mUids;
397         final String[] names2 = other.mNames;
398         boolean changed = false;
399         int i1 = 0, i2 = 0;
400         if (DEBUG) Log.d(TAG, "Remove " + other + " from " + this);
401         while (i1 < N1 && i2 < N2) {
402             if (DEBUG) Log.d(TAG, "Step: target @ " + i1 + " of " + N1 + ", other @ " + i2
403                     + " of " + N2 + ": " + uids1[i1] + " " + names1[i1]);
404             if (uids2[i2] == uids1[i1] && names2[i2].equals(names1[i1])) {
405                 if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1
406                         + ": remove " + uids1[i1] + " " + names1[i1]);
407                 N1--;
408                 changed = true;
409                 if (i1 < N1) {
410                     System.arraycopy(uids1, i1+1, uids1, i1, N1-i1);
411                     System.arraycopy(names1, i1+1, names1, i1, N1-i1);
412                 }
413                 i2++;
414             } else if (uids2[i2] > uids1[i1]
415                     || (uids2[i2] == uids1[i1] && names2[i2].compareTo(names1[i1]) > 0)) {
416                 if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1 + ": skip i1");
417                 i1++;
418             } else {
419                 if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1 + ": skip i2");
420                 i2++;
421             }
422         }
423 
424         mNum = N1;
425 
426         return changed;
427     }
428 
updateLocked(WorkSource other, boolean set, boolean returnNewbs)429     private boolean updateLocked(WorkSource other, boolean set, boolean returnNewbs) {
430         if (mNames == null && other.mNames == null) {
431             return updateUidsLocked(other, set, returnNewbs);
432         } else {
433             if (mNum > 0 && mNames == null) {
434                 throw new IllegalArgumentException("Other " + other + " has names, but target "
435                         + this + " does not");
436             }
437             if (other.mNum > 0 && other.mNames == null) {
438                 throw new IllegalArgumentException("Target " + this + " has names, but other "
439                         + other + " does not");
440             }
441             return updateUidsAndNamesLocked(other, set, returnNewbs);
442         }
443     }
444 
addWork(WorkSource cur, int newUid)445     private static WorkSource addWork(WorkSource cur, int newUid) {
446         if (cur == null) {
447             return new WorkSource(newUid);
448         }
449         cur.insert(cur.mNum, newUid);
450         return cur;
451     }
452 
updateUidsLocked(WorkSource other, boolean set, boolean returnNewbs)453     private boolean updateUidsLocked(WorkSource other, boolean set, boolean returnNewbs) {
454         int N1 = mNum;
455         int[] uids1 = mUids;
456         final int N2 = other.mNum;
457         final int[] uids2 = other.mUids;
458         boolean changed = false;
459         int i1 = 0, i2 = 0;
460         if (DEBUG) Log.d(TAG, "Update " + this + " with " + other + " set=" + set
461                 + " returnNewbs=" + returnNewbs);
462         while (i1 < N1 || i2 < N2) {
463             if (DEBUG) Log.d(TAG, "Step: target @ " + i1 + " of " + N1 + ", other @ " + i2
464                     + " of " + N2);
465             if (i1 >= N1 || (i2 < N2 && uids2[i2] < uids1[i1])) {
466                 // Need to insert a new uid.
467                 if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1
468                         + ": insert " + uids2[i2]);
469                 changed = true;
470                 if (uids1 == null) {
471                     uids1 = new int[4];
472                     uids1[0] = uids2[i2];
473                 } else if (N1 >= uids1.length) {
474                     int[] newuids = new int[(uids1.length*3)/2];
475                     if (i1 > 0) System.arraycopy(uids1, 0, newuids, 0, i1);
476                     if (i1 < N1) System.arraycopy(uids1, i1, newuids, i1+1, N1-i1);
477                     uids1 = newuids;
478                     uids1[i1] = uids2[i2];
479                 } else {
480                     if (i1 < N1) System.arraycopy(uids1, i1, uids1, i1+1, N1-i1);
481                     uids1[i1] = uids2[i2];
482                 }
483                 if (returnNewbs) {
484                     sNewbWork = addWork(sNewbWork, uids2[i2]);
485                 }
486                 N1++;
487                 i1++;
488                 i2++;
489             } else {
490                 if (!set) {
491                     // Skip uids that already exist or are not in 'other'.
492                     if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1 + ": skip");
493                     if (i2 < N2 && uids2[i2] == uids1[i1]) {
494                         i2++;
495                     }
496                     i1++;
497                 } else {
498                     // Remove any uids that don't exist in 'other'.
499                     int start = i1;
500                     while (i1 < N1 && (i2 >= N2 || uids2[i2] > uids1[i1])) {
501                         if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + ": remove " + uids1[i1]);
502                         sGoneWork = addWork(sGoneWork, uids1[i1]);
503                         i1++;
504                     }
505                     if (start < i1) {
506                         System.arraycopy(uids1, i1, uids1, start, N1-i1);
507                         N1 -= i1-start;
508                         i1 = start;
509                     }
510                     // If there is a matching uid, skip it.
511                     if (i1 < N1 && i2 < N2 && uids2[i2] == uids1[i1]) {
512                         if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1 + ": skip");
513                         i1++;
514                         i2++;
515                     }
516                 }
517             }
518         }
519 
520         mNum = N1;
521         mUids = uids1;
522 
523         return changed;
524     }
525 
526     /**
527      * Returns 0 if equal, negative if 'this' is before 'other', positive if 'this' is after 'other'.
528      */
compare(WorkSource other, int i1, int i2)529     private int compare(WorkSource other, int i1, int i2) {
530         final int diff = mUids[i1] - other.mUids[i2];
531         if (diff != 0) {
532             return diff;
533         }
534         return mNames[i1].compareTo(other.mNames[i2]);
535     }
536 
addWork(WorkSource cur, int newUid, String newName)537     private static WorkSource addWork(WorkSource cur, int newUid, String newName) {
538         if (cur == null) {
539             return new WorkSource(newUid, newName);
540         }
541         cur.insert(cur.mNum, newUid, newName);
542         return cur;
543     }
544 
updateUidsAndNamesLocked(WorkSource other, boolean set, boolean returnNewbs)545     private boolean updateUidsAndNamesLocked(WorkSource other, boolean set, boolean returnNewbs) {
546         final int N2 = other.mNum;
547         final int[] uids2 = other.mUids;
548         String[] names2 = other.mNames;
549         boolean changed = false;
550         int i1 = 0, i2 = 0;
551         if (DEBUG) Log.d(TAG, "Update " + this + " with " + other + " set=" + set
552                 + " returnNewbs=" + returnNewbs);
553         while (i1 < mNum || i2 < N2) {
554             if (DEBUG) Log.d(TAG, "Step: target @ " + i1 + " of " + mNum + ", other @ " + i2
555                     + " of " + N2);
556             int diff = -1;
557             if (i1 >= mNum || (i2 < N2 && (diff=compare(other, i1, i2)) > 0)) {
558                 // Need to insert a new uid.
559                 changed = true;
560                 if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + mNum
561                         + ": insert " + uids2[i2] + " " + names2[i2]);
562                 insert(i1, uids2[i2], names2[i2]);
563                 if (returnNewbs) {
564                     sNewbWork = addWork(sNewbWork, uids2[i2], names2[i2]);
565                 }
566                 i1++;
567                 i2++;
568             } else {
569                 if (!set) {
570                     if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + mNum + ": skip");
571                     if (i2 < N2 && diff == 0) {
572                         i2++;
573                     }
574                     i1++;
575                 } else {
576                     // Remove any uids that don't exist in 'other'.
577                     int start = i1;
578                     while (diff < 0) {
579                         if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + ": remove " + mUids[i1]
580                                 + " " + mNames[i1]);
581                         sGoneWork = addWork(sGoneWork, mUids[i1], mNames[i1]);
582                         i1++;
583                         if (i1 >= mNum) {
584                             break;
585                         }
586                         diff = i2 < N2 ? compare(other, i1, i2) : -1;
587                     }
588                     if (start < i1) {
589                         System.arraycopy(mUids, i1, mUids, start, mNum-i1);
590                         System.arraycopy(mNames, i1, mNames, start, mNum-i1);
591                         mNum -= i1-start;
592                         i1 = start;
593                     }
594                     // If there is a matching uid, skip it.
595                     if (i1 < mNum && diff == 0) {
596                         if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + mNum + ": skip");
597                         i1++;
598                         i2++;
599                     }
600                 }
601             }
602         }
603 
604         return changed;
605     }
606 
607     private void insert(int index, int uid)  {
608         if (DEBUG) Log.d(TAG, "Insert in " + this + " @ " + index + " uid " + uid);
609         if (mUids == null) {
610             mUids = new int[4];
611             mUids[0] = uid;
612             mNum = 1;
613         } else if (mNum >= mUids.length) {
614             int[] newuids = new int[(mNum*3)/2];
615             if (index > 0) {
616                 System.arraycopy(mUids, 0, newuids, 0, index);
617             }
618             if (index < mNum) {
619                 System.arraycopy(mUids, index, newuids, index+1, mNum-index);
620             }
621             mUids = newuids;
622             mUids[index] = uid;
623             mNum++;
624         } else {
625             if (index < mNum) {
626                 System.arraycopy(mUids, index, mUids, index+1, mNum-index);
627             }
628             mUids[index] = uid;
629             mNum++;
630         }
631     }
632 
633     private void insert(int index, int uid, String name)  {
634         if (mUids == null) {
635             mUids = new int[4];
636             mUids[0] = uid;
637             mNames = new String[4];
638             mNames[0] = name;
639             mNum = 1;
640         } else if (mNum >= mUids.length) {
641             int[] newuids = new int[(mNum*3)/2];
642             String[] newnames = new String[(mNum*3)/2];
643             if (index > 0) {
644                 System.arraycopy(mUids, 0, newuids, 0, index);
645                 System.arraycopy(mNames, 0, newnames, 0, index);
646             }
647             if (index < mNum) {
648                 System.arraycopy(mUids, index, newuids, index+1, mNum-index);
649                 System.arraycopy(mNames, index, newnames, index+1, mNum-index);
650             }
651             mUids = newuids;
652             mNames = newnames;
653             mUids[index] = uid;
654             mNames[index] = name;
655             mNum++;
656         } else {
657             if (index < mNum) {
658                 System.arraycopy(mUids, index, mUids, index+1, mNum-index);
659                 System.arraycopy(mNames, index, mNames, index+1, mNum-index);
660             }
661             mUids[index] = uid;
662             mNames[index] = name;
663             mNum++;
664         }
665     }
666 
667     @Override
668     public int describeContents() {
669         return 0;
670     }
671 
672     @Override
673     public void writeToParcel(Parcel dest, int flags) {
674         dest.writeInt(mNum);
675         dest.writeIntArray(mUids);
676         dest.writeStringArray(mNames);
677     }
678 
679     @Override
680     public String toString() {
681         StringBuilder result = new StringBuilder();
682         result.append("WorkSource{");
683         for (int i = 0; i < mNum; i++) {
684             if (i != 0) {
685                 result.append(", ");
686             }
687             result.append(mUids[i]);
688             if (mNames != null) {
689                 result.append(" ");
690                 result.append(mNames[i]);
691             }
692         }
693         result.append("}");
694         return result.toString();
695     }
696 
697     /** @hide */
698     public void writeToProto(ProtoOutputStream proto, long fieldId) {
699         final long workSourceToken = proto.start(fieldId);
700         for (int i = 0; i < mNum; i++) {
701             final long contentProto = proto.start(WorkSourceProto.WORK_SOURCE_CONTENTS);
702             proto.write(WorkSourceProto.WorkSourceContentProto.UID, mUids[i]);
703             if (mNames != null) {
704                 proto.write(WorkSourceProto.WorkSourceContentProto.NAME, mNames[i]);
705             }
706             proto.end(contentProto);
707         }
708         proto.end(workSourceToken);
709     }
710 
711     public static final Parcelable.Creator<WorkSource> CREATOR
712             = new Parcelable.Creator<WorkSource>() {
713         public WorkSource createFromParcel(Parcel in) {
714             return new WorkSource(in);
715         }
716         public WorkSource[] newArray(int size) {
717             return new WorkSource[size];
718         }
719     };
720 }
721