UserHandle.java revision cbd7a6ecbb7aa5a4ea146cf05f1ec254eb3e60b9
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    public static final int myUserId() {
238        return getUserId(Process.myUid());
239    }
240
241    /**
242     * Returns true if this UserHandle refers to the owner user; false otherwise.
243     * @return true if this UserHandle refers to the owner user; false otherwise.
244     * @hide
245     */
246    @SystemApi
247    public final boolean isOwner() {
248        return this.equals(OWNER);
249    }
250
251    /** @hide */
252    public UserHandle(int h) {
253        mHandle = h;
254    }
255
256    /** @hide */
257    public int getIdentifier() {
258        return mHandle;
259    }
260
261    @Override
262    public String toString() {
263        return "UserHandle{" + mHandle + "}";
264    }
265
266    @Override
267    public boolean equals(Object obj) {
268        try {
269            if (obj != null) {
270                UserHandle other = (UserHandle)obj;
271                return mHandle == other.mHandle;
272            }
273        } catch (ClassCastException e) {
274        }
275        return false;
276    }
277
278    @Override
279    public int hashCode() {
280        return mHandle;
281    }
282
283    public int describeContents() {
284        return 0;
285    }
286
287    public void writeToParcel(Parcel out, int flags) {
288        out.writeInt(mHandle);
289    }
290
291    /**
292     * Write a UserHandle to a Parcel, handling null pointers.  Must be
293     * read with {@link #readFromParcel(Parcel)}.
294     *
295     * @param h The UserHandle to be written.
296     * @param out The Parcel in which the UserHandle will be placed.
297     *
298     * @see #readFromParcel(Parcel)
299     */
300    public static void writeToParcel(UserHandle h, Parcel out) {
301        if (h != null) {
302            h.writeToParcel(out, 0);
303        } else {
304            out.writeInt(USER_NULL);
305        }
306    }
307
308    /**
309     * Read a UserHandle from a Parcel that was previously written
310     * with {@link #writeToParcel(UserHandle, Parcel)}, returning either
311     * a null or new object as appropriate.
312     *
313     * @param in The Parcel from which to read the UserHandle
314     * @return Returns a new UserHandle matching the previously written
315     * object, or null if a null had been written.
316     *
317     * @see #writeToParcel(UserHandle, Parcel)
318     */
319    public static UserHandle readFromParcel(Parcel in) {
320        int h = in.readInt();
321        return h != USER_NULL ? new UserHandle(h) : null;
322    }
323
324    public static final Parcelable.Creator<UserHandle> CREATOR
325            = new Parcelable.Creator<UserHandle>() {
326        public UserHandle createFromParcel(Parcel in) {
327            return new UserHandle(in);
328        }
329
330        public UserHandle[] newArray(int size) {
331            return new UserHandle[size];
332        }
333    };
334
335    /**
336     * Instantiate a new UserHandle from the data in a Parcel that was
337     * previously written with {@link #writeToParcel(Parcel, int)}.  Note that you
338     * must not use this with data written by
339     * {@link #writeToParcel(UserHandle, Parcel)} since it is not possible
340     * to handle a null UserHandle here.
341     *
342     * @param in The Parcel containing the previously written UserHandle,
343     * positioned at the location in the buffer where it was written.
344     */
345    public UserHandle(Parcel in) {
346        mHandle = in.readInt();
347    }
348}
349