• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.os;
18 
19 import android.annotation.AppIdInt;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SystemApi;
23 import android.annotation.TestApi;
24 import android.annotation.UserIdInt;
25 import android.compat.annotation.UnsupportedAppUsage;
26 import android.util.SparseArray;
27 
28 import com.android.internal.annotations.GuardedBy;
29 import com.android.internal.annotations.VisibleForTesting;
30 
31 import java.io.PrintWriter;
32 import java.util.ArrayList;
33 import java.util.List;
34 import java.util.Random;
35 
36 /**
37  * Representation of a user on the device.
38  */
39 @android.ravenwood.annotation.RavenwoodKeepWholeClass
40 public final class UserHandle implements Parcelable {
41     // NOTE: keep logic in sync with system/core/libcutils/multiuser.c
42 
43     /**
44      * @hide Range of uids allocated for a user.
45      */
46     @UnsupportedAppUsage
47     public static final int PER_USER_RANGE = 100000;
48 
49     /** @hide A user id to indicate all users on the device */
50     @UnsupportedAppUsage
51     @TestApi
52     public static final @UserIdInt int USER_ALL = -1;
53 
54     /** @hide A user handle to indicate all users on the device */
55     @SystemApi
56     public static final @NonNull UserHandle ALL = new UserHandle(USER_ALL);
57 
58     /** @hide A user id to indicate the currently active user */
59     @UnsupportedAppUsage
60     @TestApi
61     public static final @UserIdInt int USER_CURRENT = -2;
62 
63     /** @hide A user handle to indicate the current user of the device */
64     @SystemApi
65     public static final @NonNull UserHandle CURRENT = new UserHandle(USER_CURRENT);
66 
67     /** @hide A user id to indicate that we would like to send to the current
68      *  user, but if this is calling from a user process then we will send it
69      *  to the caller's user instead of failing with a security exception */
70     @UnsupportedAppUsage
71     public static final @UserIdInt int USER_CURRENT_OR_SELF = -3;
72 
73     /** @hide A user handle to indicate that we would like to send to the current
74      *  user, but if this is calling from a user process then we will send it
75      *  to the caller's user instead of failing with a security exception */
76     @UnsupportedAppUsage
77     public static final @NonNull UserHandle CURRENT_OR_SELF = new UserHandle(USER_CURRENT_OR_SELF);
78 
79     /** @hide An undefined user id */
80     @UnsupportedAppUsage
81     @TestApi
82     public static final @UserIdInt int USER_NULL = -10000;
83 
84     private static final @NonNull UserHandle NULL = new UserHandle(USER_NULL);
85 
86     /**
87      * @hide A user id constant to indicate the "owner" user of the device
88      * @deprecated Consider using either {@link UserHandle#USER_SYSTEM} constant or
89      * check the target user's flag {@link android.content.pm.UserInfo#isAdmin}.
90      */
91     @UnsupportedAppUsage
92     @Deprecated
93     public static final @UserIdInt int USER_OWNER = 0;
94 
95     /**
96      * @hide A user handle to indicate the primary/owner user of the device
97      * @deprecated Consider using either {@link UserHandle#SYSTEM} constant or
98      * check the target user's flag {@link android.content.pm.UserInfo#isAdmin}.
99      */
100     @UnsupportedAppUsage
101     @Deprecated
102     public static final @NonNull UserHandle OWNER = new UserHandle(USER_OWNER);
103 
104     /** @hide A user id constant to indicate the "system" user of the device */
105     @UnsupportedAppUsage
106     @TestApi
107     public static final @UserIdInt int USER_SYSTEM = 0;
108 
109     /** @hide A user serial constant to indicate the "system" user of the device */
110     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
111     public static final int USER_SERIAL_SYSTEM = 0;
112 
113     /** @hide A user handle to indicate the "system" user of the device */
114     @SystemApi
115     public static final @NonNull UserHandle SYSTEM = new UserHandle(USER_SYSTEM);
116 
117     /**
118      * @hide Enable multi-user related side effects. Set this to false if
119      * there are problems with single user use-cases.
120      */
121     @UnsupportedAppUsage
122     public static final boolean MU_ENABLED = true;
123 
124     /** @hide */
125     @TestApi
126     public static final int MIN_SECONDARY_USER_ID = 10;
127 
128     /** @hide */
129     public static final int MAX_SECONDARY_USER_ID =
130             Integer.MAX_VALUE / UserHandle.PER_USER_RANGE - 1;
131 
132     /**
133      * (Arbitrary) user handle cache size.
134      * {@link #CACHED_USER_HANDLES} caches user handles in the range of
135      * [{@link #MIN_SECONDARY_USER_ID}, {@link #MIN_SECONDARY_USER_ID} + {@link #NUM_CACHED_USERS}).
136      *
137      * For other users, we cache UserHandles in {link #sExtraUserHandleCache}.
138      *
139      * Normally, {@link #CACHED_USER_HANDLES} should cover all existing users, but use
140      * {link #sExtraUserHandleCache} to ensure {@link UserHandle#of} will not cause too many
141      * object allocations even if the device happens to have a secondary user with a large number
142      * (e.g. the user kept creating and removing the guest user?).
143      */
144     private static final int NUM_CACHED_USERS = MU_ENABLED ? 8 : 0;
145 
146     /** @see #NUM_CACHED_USERS} */
147     private static final UserHandle[] CACHED_USER_HANDLES = new UserHandle[NUM_CACHED_USERS];
148 
149     /**
150      * Extra cache for users beyond CACHED_USER_HANDLES.
151      *
152      * @see #NUM_CACHED_USERS
153      * @hide
154      */
155     @GuardedBy("sExtraUserHandleCache")
156     @VisibleForTesting
157     public static final SparseArray<UserHandle> sExtraUserHandleCache = new SparseArray<>(0);
158 
159     /**
160      * Max size of {@link #sExtraUserHandleCache}. Once it reaches this size, we select
161      * an element to remove at random.
162      *
163      * @hide
164      */
165     @VisibleForTesting
166     public static final int MAX_EXTRA_USER_HANDLE_CACHE_SIZE = 32;
167 
168     static {
169         // Not lazily initializing the cache, so that we can share them across processes.
170         // (We'll create them in zygote.)
171         for (int i = 0; i < CACHED_USER_HANDLES.length; i++) {
172             CACHED_USER_HANDLES[i] = new UserHandle(MIN_SECONDARY_USER_ID + i);
173         }
174     }
175 
176     /** @hide */
177     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
178     public static final int ERR_GID = -1;
179     /** @hide */
180     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
181     public static final int AID_ROOT = android.os.Process.ROOT_UID;
182     /** @hide */
183     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
184     public static final int AID_APP_START = android.os.Process.FIRST_APPLICATION_UID;
185     /** @hide */
186     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
187     public static final int AID_APP_END = android.os.Process.LAST_APPLICATION_UID;
188     /** @hide */
189     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
190     public static final int AID_SHARED_GID_START = android.os.Process.FIRST_SHARED_APPLICATION_GID;
191     /** @hide */
192     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
193     public static final int AID_CACHE_GID_START = android.os.Process.FIRST_APPLICATION_CACHE_GID;
194 
195     /** The userId represented by this UserHandle. */
196     @UnsupportedAppUsage
197     final @UserIdInt int mHandle;
198 
199     /**
200      * Checks to see if the user id is the same for the two uids, i.e., they belong to the same
201      * user.
202      * @hide
203      */
isSameUser(int uid1, int uid2)204     public static boolean isSameUser(int uid1, int uid2) {
205         return getUserId(uid1) == getUserId(uid2);
206     }
207 
208     /**
209      * Checks to see if both uids are referring to the same app id, ignoring the user id part of the
210      * uids.
211      * @param uid1 uid to compare
212      * @param uid2 other uid to compare
213      * @return whether the appId is the same for both uids
214      * @hide
215      */
216     @UnsupportedAppUsage
isSameApp(int uid1, int uid2)217     public static boolean isSameApp(int uid1, int uid2) {
218         return getAppId(uid1) == getAppId(uid2);
219     }
220 
221     /**
222      * Whether a UID is an "isolated" UID.
223      * @hide
224      */
225     @UnsupportedAppUsage
isIsolated(int uid)226     public static boolean isIsolated(int uid) {
227         if (uid > 0) {
228             return Process.isIsolated(uid);
229         } else {
230             return false;
231         }
232     }
233 
234     /**
235      * Whether a UID belongs to a regular app. *Note* "Not a regular app" does not mean
236      * "it's system", because of isolated UIDs. Use {@link #isCore} for that.
237      * @hide
238      */
239     @UnsupportedAppUsage
240     @TestApi
isApp(int uid)241     public static boolean isApp(int uid) {
242         if (uid > 0) {
243             final int appId = getAppId(uid);
244             return appId >= Process.FIRST_APPLICATION_UID && appId <= Process.LAST_APPLICATION_UID;
245         } else {
246             return false;
247         }
248     }
249 
250     /**
251      * Whether a UID belongs to a system core component or not.
252      * @hide
253      */
isCore(int uid)254     public static boolean isCore(int uid) {
255         if (uid >= 0) {
256             final int appId = getAppId(uid);
257             return appId < Process.FIRST_APPLICATION_UID;
258         } else {
259             return false;
260         }
261     }
262 
263     /**
264      * Whether a UID belongs to a shared app gid.
265      * @hide
266      */
isSharedAppGid(int uid)267     public static boolean isSharedAppGid(int uid) {
268         return getAppIdFromSharedAppGid(uid) != -1;
269     }
270 
271     /**
272      * Returns the user for a given uid.
273      * @param uid A uid for an application running in a particular user.
274      * @return A {@link UserHandle} for that user.
275      */
getUserHandleForUid(int uid)276     public static UserHandle getUserHandleForUid(int uid) {
277         return of(getUserId(uid));
278     }
279 
280     /**
281      * Returns the user id for a given uid.
282      * @hide
283      */
284     @UnsupportedAppUsage
285     @TestApi
getUserId(int uid)286     public static @UserIdInt int getUserId(int uid) {
287         if (MU_ENABLED) {
288             return uid / PER_USER_RANGE;
289         } else {
290             return UserHandle.USER_SYSTEM;
291         }
292     }
293 
294     /** @hide */
295     @UnsupportedAppUsage
getCallingUserId()296     public static @UserIdInt int getCallingUserId() {
297         return getUserId(Binder.getCallingUid());
298     }
299 
300     /** @hide */
getCallingAppId()301     public static @AppIdInt int getCallingAppId() {
302         return getAppId(Binder.getCallingUid());
303     }
304 
305     /** @hide */
306     @NonNull
fromUserHandles(@onNull List<UserHandle> users)307     public static int[] fromUserHandles(@NonNull List<UserHandle> users) {
308         int[] userIds = new int[users.size()];
309         for (int i = 0; i < userIds.length; ++i) {
310             userIds[i] = users.get(i).getIdentifier();
311         }
312         return userIds;
313     }
314 
315     /** @hide */
316     @NonNull
toUserHandles(@onNull int[] userIds)317     public static List<UserHandle> toUserHandles(@NonNull int[] userIds) {
318         List<UserHandle> users = new ArrayList<>(userIds.length);
319         for (int i = 0; i < userIds.length; ++i) {
320             users.add(UserHandle.of(userIds[i]));
321         }
322         return users;
323     }
324 
325     /** @hide */
326     @SystemApi
of(@serIdInt int userId)327     public static UserHandle of(@UserIdInt int userId) {
328         if (userId == USER_SYSTEM) {
329             return SYSTEM; // Most common.
330         }
331         // These are sequential; so use a switch. Maybe they'll be optimized to a table lookup.
332         switch (userId) {
333             case USER_ALL:
334                 return ALL;
335 
336             case USER_CURRENT:
337                 return CURRENT;
338 
339             case USER_CURRENT_OR_SELF:
340                 return CURRENT_OR_SELF;
341         }
342         if (userId >= MIN_SECONDARY_USER_ID
343                 && userId < (MIN_SECONDARY_USER_ID + CACHED_USER_HANDLES.length)) {
344             return CACHED_USER_HANDLES[userId - MIN_SECONDARY_USER_ID];
345         }
346         if (userId == USER_NULL) { // Not common.
347             return NULL;
348         }
349         return getUserHandleFromExtraCache(userId);
350     }
351 
352     /** @hide */
353     @VisibleForTesting
getUserHandleFromExtraCache(@serIdInt int userId)354     public static UserHandle getUserHandleFromExtraCache(@UserIdInt int userId) {
355         synchronized (sExtraUserHandleCache) {
356             final UserHandle extraCached = sExtraUserHandleCache.get(userId);
357             if (extraCached != null) {
358                 return extraCached;
359             }
360             if (sExtraUserHandleCache.size() >= MAX_EXTRA_USER_HANDLE_CACHE_SIZE) {
361                 sExtraUserHandleCache.removeAt(
362                         (new Random()).nextInt(MAX_EXTRA_USER_HANDLE_CACHE_SIZE));
363             }
364             final UserHandle newHandle = new UserHandle(userId);
365             sExtraUserHandleCache.put(userId, newHandle);
366             return newHandle;
367         }
368     }
369 
370     /**
371      * Returns the uid that is composed from the userId and the appId.
372      * @hide
373      */
374     @UnsupportedAppUsage
375     @TestApi
getUid(@serIdInt int userId, @AppIdInt int appId)376     public static int getUid(@UserIdInt int userId, @AppIdInt int appId) {
377         if (MU_ENABLED && appId >= 0) {
378             return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);
379         } else {
380             return appId;
381         }
382     }
383 
384     /**
385      * Returns the uid representing the given appId for this UserHandle.
386      *
387      * @param appId the AppId to compose the uid
388      * @return the uid representing the given appId for this UserHandle
389      * @hide
390      */
391     @SystemApi
getUid(@ppIdInt int appId)392     public int getUid(@AppIdInt int appId) {
393         return getUid(getIdentifier(), appId);
394     }
395 
396     /**
397      * Returns the app id (or base uid) for a given uid, stripping out the user id from it.
398      * @hide
399      */
400     @SystemApi
getAppId(int uid)401     public static @AppIdInt int getAppId(int uid) {
402         return uid % PER_USER_RANGE;
403     }
404 
405     /**
406      * Returns the gid shared between all apps with this userId.
407      * @hide
408      */
getUserGid(@serIdInt int userId)409     public static int getUserGid(@UserIdInt int userId) {
410         return getUid(userId, Process.SHARED_USER_GID);
411     }
412 
413     /**
414      * Returns the gid shared between all users with the app that this uid represents, or -1 if the
415      * uid is invalid.
416      * @hide
417      */
418     @SystemApi
getSharedAppGid(int uid)419     public static int getSharedAppGid(int uid) {
420         return getSharedAppGid(getUserId(uid), getAppId(uid));
421     }
422 
423     /** @hide */
getSharedAppGid(@serIdInt int userId, @AppIdInt int appId)424     public static int getSharedAppGid(@UserIdInt int userId, @AppIdInt int appId) {
425         if (appId >= AID_APP_START && appId <= AID_APP_END) {
426             return (appId - AID_APP_START) + AID_SHARED_GID_START;
427         } else if (appId >= AID_ROOT && appId <= AID_APP_START) {
428             return appId;
429         } else {
430             return -1;
431         }
432     }
433 
434     /**
435      * Returns the app id for a given shared app gid. Returns -1 if the ID is invalid.
436      * @hide
437      */
438     @UnsupportedAppUsage
getAppIdFromSharedAppGid(int gid)439     public static @AppIdInt int getAppIdFromSharedAppGid(int gid) {
440         final int appId = getAppId(gid) + Process.FIRST_APPLICATION_UID
441                 - Process.FIRST_SHARED_APPLICATION_GID;
442         if (appId < 0 || appId >= Process.FIRST_SHARED_APPLICATION_GID) {
443             return -1;
444         }
445         return appId;
446     }
447 
448     /** @hide */
getCacheAppGid(int uid)449     public static int getCacheAppGid(int uid) {
450         return getCacheAppGid(getUserId(uid), getAppId(uid));
451     }
452 
453     /** @hide */
getCacheAppGid(@serIdInt int userId, @AppIdInt int appId)454     public static int getCacheAppGid(@UserIdInt int userId, @AppIdInt int appId) {
455         if (appId >= AID_APP_START && appId <= AID_APP_END) {
456             return getUid(userId, (appId - AID_APP_START) + AID_CACHE_GID_START);
457         } else {
458             return -1;
459         }
460     }
461 
462     /**
463      * Generate a text representation of the uid, breaking out its individual
464      * components -- user, app, isolated, etc.
465      * @hide
466      */
formatUid(StringBuilder sb, int uid)467     public static void formatUid(StringBuilder sb, int uid) {
468         if (uid < Process.FIRST_APPLICATION_UID) {
469             sb.append(uid);
470         } else {
471             sb.append('u');
472             sb.append(getUserId(uid));
473             final int appId = getAppId(uid);
474             if (isIsolated(appId)) {
475                 if (appId > Process.FIRST_ISOLATED_UID) {
476                     sb.append('i');
477                     sb.append(appId - Process.FIRST_ISOLATED_UID);
478                 } else {
479                     sb.append("ai");
480                     sb.append(appId - Process.FIRST_APP_ZYGOTE_ISOLATED_UID);
481                 }
482             } else if (appId >= Process.FIRST_APPLICATION_UID) {
483                 sb.append('a');
484                 sb.append(appId - Process.FIRST_APPLICATION_UID);
485             } else {
486                 sb.append('s');
487                 sb.append(appId);
488             }
489         }
490     }
491 
492     /**
493      * Generate a text representation of the uid, breaking out its individual
494      * components -- user, app, isolated, etc.
495      *
496      * @param uid The uid to format
497      * @return A string representing the UID with its individual components broken out
498      * @hide
499      */
500     @SystemApi
501     @NonNull
formatUid(int uid)502     public static String formatUid(int uid) {
503         StringBuilder sb = new StringBuilder();
504         formatUid(sb, uid);
505         return sb.toString();
506     }
507 
508     /**
509      * Generate a text representation of the uid, breaking out its individual
510      * components -- user, app, isolated, etc.
511      * @hide
512      */
513     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
formatUid(PrintWriter pw, int uid)514     public static void formatUid(PrintWriter pw, int uid) {
515         if (uid < Process.FIRST_APPLICATION_UID) {
516             pw.print(uid);
517         } else {
518             pw.print('u');
519             pw.print(getUserId(uid));
520             final int appId = getAppId(uid);
521             if (isIsolated(appId)) {
522                 if (appId > Process.FIRST_ISOLATED_UID) {
523                     pw.print('i');
524                     pw.print(appId - Process.FIRST_ISOLATED_UID);
525                 } else {
526                     pw.print("ai");
527                     pw.print(appId - Process.FIRST_APP_ZYGOTE_ISOLATED_UID);
528                 }
529             } else if (appId >= Process.FIRST_APPLICATION_UID) {
530                 pw.print('a');
531                 pw.print(appId - Process.FIRST_APPLICATION_UID);
532             } else {
533                 pw.print('s');
534                 pw.print(appId);
535             }
536         }
537     }
538 
539     /** @hide */
parseUserArg(String arg)540     public static @UserIdInt int parseUserArg(String arg) {
541         int userId;
542         if ("all".equals(arg)) {
543             userId = UserHandle.USER_ALL;
544         } else if ("current".equals(arg) || "cur".equals(arg)) {
545             userId = UserHandle.USER_CURRENT;
546         } else {
547             try {
548                 userId = Integer.parseInt(arg);
549             } catch (NumberFormatException e) {
550                 throw new IllegalArgumentException("Bad user number: " + arg);
551             }
552         }
553         return userId;
554     }
555 
556     /**
557      * Returns the user id of the current process
558      * @return user id of the current process
559      * @hide
560      */
561     @SystemApi
myUserId()562     public static @UserIdInt int myUserId() {
563         return getUserId(Process.myUid());
564     }
565 
566     /**
567      * Returns true if this UserHandle refers to the owner user; false otherwise.
568      * @return true if this UserHandle refers to the owner user; false otherwise.
569      * @hide
570      * @deprecated please use {@link #isSystem()} or check for
571      * {@link android.content.pm.UserInfo#isPrimary()}
572      * {@link android.content.pm.UserInfo#isAdmin()} based on your particular use case.
573      */
574     @Deprecated
575     @SystemApi
isOwner()576     public boolean isOwner() {
577         return this.equals(OWNER);
578     }
579 
580     /**
581      * @return true if this UserHandle refers to the system user; false otherwise.
582      * @hide
583      */
584     @SystemApi
isSystem()585     public boolean isSystem() {
586         return this.equals(SYSTEM);
587     }
588 
589     /** @hide */
590     @UnsupportedAppUsage
UserHandle(@serIdInt int userId)591     public UserHandle(@UserIdInt int userId) {
592         mHandle = userId;
593     }
594 
595     /**
596      * Returns the userId stored in this UserHandle.
597      * @hide
598      */
599     @SystemApi
getIdentifier()600     public @UserIdInt int getIdentifier() {
601         return mHandle;
602     }
603 
604     @Override
toString()605     public String toString() {
606         return "UserHandle{" + mHandle + "}";
607     }
608 
609     @Override
equals(@ullable Object obj)610     public boolean equals(@Nullable Object obj) {
611         if (obj instanceof UserHandle) {
612             UserHandle other = (UserHandle) obj;
613             return mHandle == other.mHandle;
614         }
615         return false;
616     }
617 
618     @Override
hashCode()619     public int hashCode() {
620         return mHandle;
621     }
622 
describeContents()623     public int describeContents() {
624         return 0;
625     }
626 
writeToParcel(Parcel out, int flags)627     public void writeToParcel(Parcel out, int flags) {
628         out.writeInt(mHandle);
629     }
630 
631     /**
632      * Write a UserHandle to a Parcel, handling null pointers.  Must be
633      * read with {@link #readFromParcel(Parcel)}.
634      *
635      * @param h The UserHandle to be written.
636      * @param out The Parcel in which the UserHandle will be placed.
637      *
638      * @see #readFromParcel(Parcel)
639      */
writeToParcel(UserHandle h, Parcel out)640     public static void writeToParcel(UserHandle h, Parcel out) {
641         if (h != null) {
642             h.writeToParcel(out, 0);
643         } else {
644             out.writeInt(USER_NULL);
645         }
646     }
647 
648     /**
649      * Read a UserHandle from a Parcel that was previously written
650      * with {@link #writeToParcel(UserHandle, Parcel)}, returning either
651      * a null or new object as appropriate.
652      *
653      * @param in The Parcel from which to read the UserHandle
654      * @return Returns a new UserHandle matching the previously written
655      * object, or null if a null had been written.
656      *
657      * @see #writeToParcel(UserHandle, Parcel)
658      */
readFromParcel(Parcel in)659     public static UserHandle readFromParcel(Parcel in) {
660         int h = in.readInt();
661         return h != USER_NULL ? new UserHandle(h) : null;
662     }
663 
664     public static final @android.annotation.NonNull Parcelable.Creator<UserHandle> CREATOR
665             = new Parcelable.Creator<UserHandle>() {
666         public UserHandle createFromParcel(Parcel in) {
667             // Try to avoid allocation; use of() here. Keep this and the constructor below
668             // in sync.
669             return UserHandle.of(in.readInt());
670         }
671 
672         public UserHandle[] newArray(int size) {
673             return new UserHandle[size];
674         }
675     };
676 
677     /**
678      * Instantiate a new UserHandle from the data in a Parcel that was
679      * previously written with {@link #writeToParcel(Parcel, int)}.  Note that you
680      * must not use this with data written by
681      * {@link #writeToParcel(UserHandle, Parcel)} since it is not possible
682      * to handle a null UserHandle here.
683      *
684      * @param in The Parcel containing the previously written UserHandle,
685      * positioned at the location in the buffer where it was written.
686      */
UserHandle(Parcel in)687     public UserHandle(Parcel in) {
688         mHandle = in.readInt(); // Keep this and createFromParcel() in sync.
689     }
690 }
691