UserHandle.java revision 0e8d7d63ba439cc0604af7055679dae3d30fdc48
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
17package android.os;
18
19import android.annotation.SystemApi;
20import android.util.SparseArray;
21
22import java.io.PrintWriter;
23import java.util.HashMap;
24
25/**
26 * Representation of a user on the device.
27 */
28public final class UserHandle implements Parcelable {
29    /**
30     * @hide Range of uids allocated for a user.
31     */
32    public static final int PER_USER_RANGE = 100000;
33
34    /** @hide A user id to indicate all users on the device */
35    public static final int USER_ALL = -1;
36
37    /** @hide A user handle to indicate all users on the device */
38    public static final UserHandle ALL = new UserHandle(USER_ALL);
39
40    /** @hide A user id to indicate the currently active user */
41    public static final int USER_CURRENT = -2;
42
43    /** @hide A user handle to indicate the current user of the device */
44    public static final UserHandle CURRENT = new UserHandle(USER_CURRENT);
45
46    /** @hide A user id to indicate that we would like to send to the current
47     *  user, but if this is calling from a user process then we will send it
48     *  to the caller's user instead of failing wiht a security exception */
49    public static final int USER_CURRENT_OR_SELF = -3;
50
51    /** @hide A user handle to indicate that we would like to send to the current
52     *  user, but if this is calling from a user process then we will send it
53     *  to the caller's user instead of failing wiht a security exception */
54    public static final UserHandle CURRENT_OR_SELF = new UserHandle(USER_CURRENT_OR_SELF);
55
56    /** @hide An undefined user id */
57    public static final int USER_NULL = -10000;
58
59    /** @hide A user id constant to indicate the "owner" user of the device */
60    public static final int USER_OWNER = 0;
61
62    /** @hide A user handle to indicate the primary/owner user of the device */
63    public static final UserHandle OWNER = new UserHandle(USER_OWNER);
64
65    /**
66     * @hide Enable multi-user related side effects. Set this to false if
67     * there are problems with single user use-cases.
68     */
69    public static final boolean MU_ENABLED = true;
70
71    final int mHandle;
72
73    private static final SparseArray<UserHandle> userHandles = new SparseArray<UserHandle>();
74
75    /**
76     * Checks to see if the user id is the same for the two uids, i.e., they belong to the same
77     * user.
78     * @hide
79     */
80    public static final boolean isSameUser(int uid1, int uid2) {
81        return getUserId(uid1) == getUserId(uid2);
82    }
83
84    /**
85     * Checks to see if both uids are referring to the same app id, ignoring the user id part of the
86     * uids.
87     * @param uid1 uid to compare
88     * @param uid2 other uid to compare
89     * @return whether the appId is the same for both uids
90     * @hide
91     */
92    public static final boolean isSameApp(int uid1, int uid2) {
93        return getAppId(uid1) == getAppId(uid2);
94    }
95
96    /** @hide */
97    public static final boolean isIsolated(int uid) {
98        if (uid > 0) {
99            final int appId = getAppId(uid);
100            return appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID;
101        } else {
102            return false;
103        }
104    }
105
106    /** @hide */
107    public static boolean isApp(int uid) {
108        if (uid > 0) {
109            final int appId = getAppId(uid);
110            return appId >= Process.FIRST_APPLICATION_UID && appId <= Process.LAST_APPLICATION_UID;
111        } else {
112            return false;
113        }
114    }
115
116    /**
117     * Returns the user id for a given uid.
118     * @hide
119     */
120    public static final int getUserId(int uid) {
121        if (MU_ENABLED) {
122            return uid / PER_USER_RANGE;
123        } else {
124            return 0;
125        }
126    }
127
128    /** @hide */
129    public static final int getCallingUserId() {
130        return getUserId(Binder.getCallingUid());
131    }
132
133    /** @hide */
134    public static final UserHandle getCallingUserHandle() {
135        int userId = getUserId(Binder.getCallingUid());
136        UserHandle userHandle = userHandles.get(userId);
137        // Intentionally not synchronized to save time
138        if (userHandle == null) {
139            userHandle = new UserHandle(userId);
140            userHandles.put(userId, userHandle);
141        }
142        return userHandle;
143    }
144
145    /**
146     * Returns the uid that is composed from the userId and the appId.
147     * @hide
148     */
149    public static final int getUid(int userId, int appId) {
150        if (MU_ENABLED) {
151            return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);
152        } else {
153            return appId;
154        }
155    }
156
157    /**
158     * Returns the app id (or base uid) for a given uid, stripping out the user id from it.
159     * @hide
160     */
161    public static final int getAppId(int uid) {
162        return uid % PER_USER_RANGE;
163    }
164
165    /**
166     * Returns the gid shared between all apps with this userId.
167     * @hide
168     */
169    public static final int getUserGid(int userId) {
170        return getUid(userId, Process.SHARED_USER_GID);
171    }
172
173    /**
174     * Returns the shared app gid for a given uid or appId.
175     * @hide
176     */
177    public static final int getSharedAppGid(int id) {
178        return Process.FIRST_SHARED_APPLICATION_GID + (id % PER_USER_RANGE)
179                - Process.FIRST_APPLICATION_UID;
180    }
181
182    /**
183     * Generate a text representation of the uid, breaking out its individual
184     * components -- user, app, isolated, etc.
185     * @hide
186     */
187    public static void formatUid(StringBuilder sb, int uid) {
188        if (uid < Process.FIRST_APPLICATION_UID) {
189            sb.append(uid);
190        } else {
191            sb.append('u');
192            sb.append(getUserId(uid));
193            final int appId = getAppId(uid);
194            if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) {
195                sb.append('i');
196                sb.append(appId - Process.FIRST_ISOLATED_UID);
197            } else if (appId >= Process.FIRST_APPLICATION_UID) {
198                sb.append('a');
199                sb.append(appId - Process.FIRST_APPLICATION_UID);
200            } else {
201                sb.append('s');
202                sb.append(appId);
203            }
204        }
205    }
206
207    /**
208     * Generate a text representation of the uid, breaking out its individual
209     * components -- user, app, isolated, etc.
210     * @hide
211     */
212    public static void formatUid(PrintWriter pw, int uid) {
213        if (uid < Process.FIRST_APPLICATION_UID) {
214            pw.print(uid);
215        } else {
216            pw.print('u');
217            pw.print(getUserId(uid));
218            final int appId = getAppId(uid);
219            if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) {
220                pw.print('i');
221                pw.print(appId - Process.FIRST_ISOLATED_UID);
222            } else if (appId >= Process.FIRST_APPLICATION_UID) {
223                pw.print('a');
224                pw.print(appId - Process.FIRST_APPLICATION_UID);
225            } else {
226                pw.print('s');
227                pw.print(appId);
228            }
229        }
230    }
231
232    /**
233     * Returns the user id of the current process
234     * @return user id of the current process
235     * @hide
236     */
237    @SystemApi
238    public static final int myUserId() {
239        return getUserId(Process.myUid());
240    }
241
242    /**
243     * Returns true if this UserHandle refers to the owner user; false otherwise.
244     * @return true if this UserHandle refers to the owner user; false otherwise.
245     * @hide
246     */
247    @SystemApi
248    public final boolean isOwner() {
249        return this.equals(OWNER);
250    }
251
252    /** @hide */
253    public UserHandle(int h) {
254        mHandle = h;
255    }
256
257    /**
258     * Returns the userId stored in this UserHandle.
259     * @hide
260     */
261    @SystemApi
262    public int getIdentifier() {
263        return mHandle;
264    }
265
266    @Override
267    public String toString() {
268        return "UserHandle{" + mHandle + "}";
269    }
270
271    @Override
272    public boolean equals(Object obj) {
273        try {
274            if (obj != null) {
275                UserHandle other = (UserHandle)obj;
276                return mHandle == other.mHandle;
277            }
278        } catch (ClassCastException e) {
279        }
280        return false;
281    }
282
283    @Override
284    public int hashCode() {
285        return mHandle;
286    }
287
288    public int describeContents() {
289        return 0;
290    }
291
292    public void writeToParcel(Parcel out, int flags) {
293        out.writeInt(mHandle);
294    }
295
296    /**
297     * Write a UserHandle to a Parcel, handling null pointers.  Must be
298     * read with {@link #readFromParcel(Parcel)}.
299     *
300     * @param h The UserHandle to be written.
301     * @param out The Parcel in which the UserHandle will be placed.
302     *
303     * @see #readFromParcel(Parcel)
304     */
305    public static void writeToParcel(UserHandle h, Parcel out) {
306        if (h != null) {
307            h.writeToParcel(out, 0);
308        } else {
309            out.writeInt(USER_NULL);
310        }
311    }
312
313    /**
314     * Read a UserHandle from a Parcel that was previously written
315     * with {@link #writeToParcel(UserHandle, Parcel)}, returning either
316     * a null or new object as appropriate.
317     *
318     * @param in The Parcel from which to read the UserHandle
319     * @return Returns a new UserHandle matching the previously written
320     * object, or null if a null had been written.
321     *
322     * @see #writeToParcel(UserHandle, Parcel)
323     */
324    public static UserHandle readFromParcel(Parcel in) {
325        int h = in.readInt();
326        return h != USER_NULL ? new UserHandle(h) : null;
327    }
328
329    public static final Parcelable.Creator<UserHandle> CREATOR
330            = new Parcelable.Creator<UserHandle>() {
331        public UserHandle createFromParcel(Parcel in) {
332            return new UserHandle(in);
333        }
334
335        public UserHandle[] newArray(int size) {
336            return new UserHandle[size];
337        }
338    };
339
340    /**
341     * Instantiate a new UserHandle from the data in a Parcel that was
342     * previously written with {@link #writeToParcel(Parcel, int)}.  Note that you
343     * must not use this with data written by
344     * {@link #writeToParcel(UserHandle, Parcel)} since it is not possible
345     * to handle a null UserHandle here.
346     *
347     * @param in The Parcel containing the previously written UserHandle,
348     * positioned at the location in the buffer where it was written.
349     */
350    public UserHandle(Parcel in) {
351        mHandle = in.readInt();
352    }
353}
354