Android的多用户有个东西,叫UserHandle,跟多用户相关。现在记录一下。
一.每个进程看看
root 3051 2 0 0 rescuer_th 0000000000 S kbase_event
system 3138 522 2002840 89588 SyS_epoll_ 70add58a60 S com.hehe.usbselection
u0_a23 3342 523 1475732 94212 SyS_epoll_ 00edb6b538 S com.android.mms
u0_a2 3395 522 2010492 95944 SyS_epoll_ 70add58a60 S com.android.providers.calendar
u0_a101 3518 523 1445740 79736 SyS_epoll_ 00edb6b538 S com.hehe.activation
root 3623 2 0 0 worker_thr 0000000000 S kworker/2:3
u0_a13 4307 522 2332516 150276 SyS_epoll_ 70add58a60 S com.google.android.gms.unstable
root 4487 2 0 0 rescuer_th 0000000000 S kbase_event
system 4503 522 2008192 92252 SyS_epoll_ 70add58a60 S com.hehe.ota
第一个字段就是进程所属的uid,普通应用的uid都是单独的。例如com.android.mms,com.hehe.activation的uid都是单独的,一个叫u0_a23,一个叫u0_a101。
而也可以看到com.hehe.usbselection,com.hehe.ota两个进程的uid都是system,两个进程同享了同一个uid。这种可以同享的uid叫做shareuid。同享uid的进程可以相互同享资源。
二.uid不会改变
应用安装后,系统重启和应用重启都不会改变uid。uid记录在data/system/packages.xml中。可以dumpsys出来看看。
dumpsys package com.android.mms |grep "uid"
uid=10023 gids=null type=0 prot=signature|privileged
三.UserHandle结构侃侃
/frameworks/base/core/java/android/os/UserHandle.java
public final class UserHandle implements Parcelable {
/**
* @hide Range of uids allocated for a user.
*/
public static final int PER_USER_RANGE = 100000; //每个用户可以有十万个uid
/** @hide A user id to indicate all users on the device */
public static final @UserIdInt int USER_ALL = -1;
/** @hide A user handle to indicate all users on the device */
public static final UserHandle ALL = new UserHandle(USER_ALL);
/** @hide A user id to indicate the currently active user */
public static final @UserIdInt int USER_CURRENT = -2;
/** @hide A user handle to indicate the current user of the device */
public static final UserHandle CURRENT = new UserHandle(USER_CURRENT);
/** @hide A user id to indicate that we would like to send to the current
* user, but if this is calling from a user process then we will send it
* to the caller's user instead of failing with a security exception */
public static final @UserIdInt int USER_CURRENT_OR_SELF = -3;
/** @hide A user handle to indicate that we would like to send to the current
* user, but if this is calling from a user process then we will send it
* to the caller's user instead of failing with a security exception */
public static final UserHandle CURRENT_OR_SELF = new UserHandle(USER_CURRENT_OR_SELF);
/** @hide An undefined user id */
public static final @UserIdInt int USER_NULL = -10000;
/**
* @hide A user id constant to indicate the "owner" user of the device
* @deprecated Consider using either {@link UserHandle#USER_SYSTEM} constant or
* check the target user's flag {@link android.content.pm.UserInfo#isAdmin}.
*/
public static final @UserIdInt int USER_OWNER = 0;
/**
* @hide A user handle to indicate the primary/owner user of the device
* @deprecated Consider using either {@link UserHandle#SYSTEM} constant or
* check the target user's flag {@link android.content.pm.UserInfo#isAdmin}.
*/
public static final UserHandle OWNER = new UserHandle(USER_OWNER);
/** @hide A user id constant to indicate the "system" user of the device */
public static final @UserIdInt int USER_SYSTEM = 0;
/** @hide A user serial constant to indicate the "system" user of the device */
public static final int USER_SERIAL_SYSTEM = 0;
/** @hide A user handle to indicate the "system" user of the device */
public static final UserHandle SYSTEM = new UserHandle(USER_SYSTEM);
/**
* @hide Enable multi-user related side effects. Set this to false if
* there are problems with single user use-cases.
*/
public static final boolean MU_ENABLED = true;
final int mHandle;
/**
* Checks to see if the user id is the same for the two uids, i.e., they belong to the same
* user.
* @hide
*/
//判断两个应用是否属于同一个用户。例如微信和微博是否都是属于老爸的。
public static boolean isSameUser(int uid1, int uid2) {
return getUserId(uid1) == getUserId(uid2);
}
/**
* Checks to see if both uids are referring to the same app id, ignoring the user id part of the
* uids.
* @param uid1 uid to compare
* @param uid2 other uid to compare
* @return whether the appId is the same for both uids
* @hide
*/
//判断两个应用是否是同一个应用。例如老爸和儿子的微信的uid传进去,返回true。
public static boolean isSameApp(int uid1, int uid2) {
return getAppId(uid1) == getAppId(uid2);
}
/** @hide */
public static boolean isIsolated(int uid) {
if (uid > 0) {
final int appId = getAppId(uid);
return appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID;
} else {
return false;
}
}
/** @hide */
public static boolean isApp(int uid) {
if (uid > 0) {
final int appId = getAppId(uid);
return appId >= Process.FIRST_APPLICATION_UID && appId <= Process.LAST_APPLICATION_UID;
} else {
return false;
}
}
//传入uid,获取userid。例如老爸的微信的uid是10080,则儿子的微信的uid是1000000+10080。最后老爸的返回值是10080/1000000=0,儿子的返回值是(1000000+10080)/1000000=1。
public static @UserIdInt int getUserId(int uid) {
if (MU_ENABLED) {
return uid / PER_USER_RANGE;
} else {
return UserHandle.USER_SYSTEM;
}
}
//传入uid,获取appid。例如老爸的微信的uid是10080,则儿子的微信的uid是1000000+10080。最后老爸的返回值是10080%1000000=10080,儿子的返回值是(1000000+10080)%1000000=10080。
public static @AppIdInt int getAppId(int uid) {
return uid % PER_USER_RANGE;
}
....................省略
可以看到,UserHandle包含三种概念:userid,uid,appid
userid:就是有多少个实际的用户罗,例如老爸很穷,要跟儿子共用一台手机,那可以跟手机将两个用户,user 0和user 1。两个用户的应用和数据是独立的。
uid:跟应用进程相关。除了sharduid的应用,每个用户的每个应用的uid不一样的。用户0的应用的uid从一万开始算。
appid:跟app相关,包名相同的appid都一样。即使是不同用户。例如你和儿子都在这台手机装了微信,但这两个微信的appid是一样的。