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