简介
UserManagerService
管理用户的系统服务,主要功能是创建和删除用户,以及查询用户信息。
Android可以支持多个用户使用系统,通常第一个在系统中注册的用户将默认成为系统管理员。
不同用户的设置各不相同,并且不同用户安装的应用及应用数据也不相同。但是系统中和硬件相关的设置则是共用的,如网络设置等。通常第一个在系统中注册的用户将成为系统管理员,可以管理手机上的其他用户。
用户切换后前面用户运行的后台进程还可以继续运行,这样进行用户切换时无须中断一些后台进行的耗时操作(如下载)。
手机设置-->用户和账号
中可以添加、删除、切换用户;访客模式下用户的所有数据(通讯录、短信、应用等)会被隐藏,访客只能查看和使用手机的基本功能,另外还可以设置访客是否可以接听电话、发送短信等权限(下面源码我们会介绍到)。
UserManagerService
服务提供UserManager
远程控制方式调用服务;
UserManager
中很多方法被@hint
隐藏了,只能内部服务使用;
设计到相关源码:
frameworks/base/core/java/android/os/UserManager.java
frameworks/base/services/core/java/com/android/server/pm/UserManagerService.java
frameworks/base/core/java/android/content/pm/UserInfo.java
frameworks/base/core/java/android/os/UserHandle.java
frameworks/base/core/java/com/android/server/pm/PackageManagerService.java
frameworks/base/core/java/com/android/server/wm/WindowManagerService.java
frameworks/base/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/core/java/android/os/Process.java
-
PackageManagerService
:在多用户环境中,所有安装的应用还是位于/data/app/
目录中,应用的数据还是保存在/data/data
下面,这些数据只对 Id 为 0 的用户即管理员用户有效,但是这些应用的数据在/data/user/<用户id>/
目录下面都会有单独的一份。 -
ActivityManagerService
:AMS中切换用户;
UserManager
UserManager
可以称为 UMS 的代理对象,它通过IUserManager mService
来与 UMS 进行进程间的通信。
UserManager
是暴露出来的应用程序接口。对于普通应用程序,提供用户数查询,用户状态判断和用户序列号查询等基本功能。普通应用没有用户操作权限。
对于系统应用,UserManager
提供了创建/删除/擦除用户、用户信息获取、用户句柄获取等用户操作的接口。
这些操作均由远程调用 UMS 服务的对应方法实现。
一、UserManager常用的几个方法介绍
1.1判断是否支持多用户模式:
public static boolean supportsMultipleUsers() {
return getMaxSupportedUsers() > 1
&& SystemProperties.getBoolean("fw.show_multiuserui",
Resources.getSystem().getBoolean(R.bool.config_enableMultiUserUI));
}
public static int getMaxSupportedUsers() {
// Don't allow multiple users on certain builds
if (android.os.Build.ID.startsWith("JVP")) return 1;
// Svelte devices don't get multi-user.
if (ActivityManager.isLowRamDeviceStatic()) return 1;
return SystemProperties.getInt("fw.max_users",
Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers));
}
首先会读取系统配置fw.show_multiuserui和fw.max_users
,如果系统没有这个配置项则从配置文件中读取默认值,配置文件在frameworks/base/core/res/res/values/config.xml
中:
1
false
也可以看到,手机上默认是不支持多用户模式的。
1.2查询用户权限
查询当前进程的用户是否拥有某个权限
UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
boolean canSendSms = userManager.hasUserRestriction(UserManager.DISALLOW_SMS);
1.3如何创建Guest用户
比如要创建一个访客用户,就可以调用UserManager.createGuest(Context context, String name)
方法来完成,这个方法使用@hide注解,对普通应用不可见不可调用,只对系统应用进程提供:
public UserInfo createGuest(Context context, String name) {
UserInfo guest = null;
try {
guest = mService.createUser(name, UserInfo.FLAG_GUEST);
if (guest != null) {
//表示跳过首次发布时的任何介绍性提示,
Settings.Secure.putStringForUser(context.getContentResolver(),
Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
}
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
return guest;
}
从代码我们可以看到createGues
t最终也会调用到UserManagerService.createUser
方法,UserInfo.FLAG_GUEST
表示用户类型,UMS会判断当前用户是否有创建和管理访客用户的权限;
UserManagerService
下面代码为设置访客的权限限制;
private void initDefaultGuestRestrictions() {
synchronized (mGuestRestrictions) {
if (mGuestRestrictions.isEmpty()) {
mGuestRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_WIFI, true);
mGuestRestrictions.putBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
mGuestRestrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, true);
mGuestRestrictions.putBoolean(UserManager.DISALLOW_SMS, true);
}
}
}
因此,Guset用户和普通用户的区别也就在于权限的
相关adb命令
获取用户信息
用adb shell dumpsys user
可以查看当前的用户情况:
UserInfo{0:机主:13} serialNo=0
Created:
Last logged in: +1h3m23s951ms ago
UserInfo{15:Guest:14} serialNo=15
Created: +2d3h37m2s326ms ago
Last logged in: +1h27m49s171ms ago
上面的打印是在UserManagerService.dump()
中打印的。
二、UserManagerService用户管理服务源码分析
UMS 是用来管理用户的系统服务,是创建、删除以及查询用户的执行者。
下面先看一下 UMS 的初始化过程。
2.1启动分析
UMS
的创建是在PackageManagerService.java
的构造函数中进行的。
sUserManager = new UserManagerService(context, this,
new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
UMS
的启动在SystemServer.java中进行
private void startBootstrapServices() {
......
mSystemServiceManager.startService(UserManagerService.LifeCycle.class);
......
}
UMS
内部类LifeCycle继承了SystemService,负责管理UMS
,并公布UserManagerService
对外的IUserManager.Stub
AIDL方法;
public static class LifeCycle extends SystemService {
private UserManagerService mUms;
/**
* @param context
*/
public LifeCycle(Context context) {
super(context);
}
@Override
public void onStart() {
mUms = UserManagerService.getInstance();
//对外公布AIDL接口服务
publishBinderService(Context.USER_SERVICE, mUms);
}
@Override
public void onBootPhase(int phase) {
//ActivityManagerService服务准备好之后,清理部分用户
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
mUms.cleanupPartialUsers();
}
}
}
-
onStart
:公布AIDL接口提供给其他系统服务或者应用使用 -
onBootPhase
:ActivityManagerService服务就绪时,删除所有部分创建的、访客用户和临时用户。
2.1构造函数
private UserManagerService(Context context, PackageManagerService pm,
UserDataPreparer userDataPreparer, Object packagesLock, File dataDir) {
mContext = context;
mPm = pm;
mPackagesLock = packagesLock;
mHandler = new MainHandler();
mUserDataPreparer = userDataPreparer;
synchronized (mPackagesLock) {
//创建system/users目录
mUsersDir = new File(dataDir, USER_INFO_DIR);
mUsersDir.mkdirs();
// Make zeroth user directory, for services to migrate their files to that location
//在system/users目录下创建一个系统用户的目录,一般系统用户的userid为0,并修改权限
File userZeroDir = new File(mUsersDir, String.valueOf(UserHandle.USER_SYSTEM));
userZeroDir.mkdirs();
FileUtils.setPermissions(mUsersDir.toString(),
FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH,
-1, -1);
//// 创建代表/data/system/users/userlist.xml文件的对象
mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
// 添加一些对访客用户的默认限制,DISALLOW_OUTGOING_CALLS和DISALLOW_SMS,不允许打电话和发信息
initDefaultGuestRestrictions();
// 读取userlist.xml文件,将用户的信息保存在mUsers列表中
// 如果该文件不存在则创建该文件
readUserListLP();
sInstance = this;
}
//注册本地服务,为系统进程服务、应用提供接口
mLocalService = new LocalService();
LocalServices.addService(UserManagerInternal.class, mLocalService);
mLockPatternUtils = new LockPatternUtils(mContext);
mUserStates.put(UserHandle.USER_SYSTEM, UserState.STATE_BOOTING);
}
然后再看一下systemReady()
函数,这里面也有一些初始化的工作,它的调用是在PackageManagerService.systemReady()
中进行的。
void systemReady() {
// 调用AppOpsManager(权限管理器)设置每个用户的权限
mAppOpsService = IAppOpsService.Stub.asInterface(
ServiceManager.getService(Context.APP_OPS_SERVICE));
synchronized (mRestrictionsLock) {
//更新系统用户权限
applyUserRestrictionsLR(UserHandle.USER_SYSTEM);
}
UserInfo currentGuestUser = findCurrentGuestUser();
if (currentGuestUser != null && !hasUserRestriction(
UserManager.DISALLOW_CONFIG_WIFI, currentGuestUser.id)) {
//如果存在访客用户,允许配置wifi权限
setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, currentGuestUser.id);
}
mContext.registerReceiver(mDisableQuietModeCallback,
new IntentFilter(ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK),
null, mHandler);
}
初始化过程中,会创建/data/system/users/
目录,以及在/data/system/users/
下面创建0/
目录,然后调用readUserListLP()
分析/data/system/users/userlist.xml
文件,这个文件保存了系统中所有用户的Id信息。
/data/system/users
目录下面的文件有:
0
0.xml
11
11.xml
userlist.xml
0/目录下面的文件:
app_idle_stats.xml photo.png settings_secure.xml
appwidgets.xml registered_services settings_ssaid.xml
fpdata runtime-permissions.xml settings_system.xml
package-restrictions.xml settings_global.xml wallpaper_info.xml
里面存放了针对该用户的各种设置数据。
userlist.xml
示例:
nextSerialNumber
指的是创建下一个用户时它的serialNumber
,version
指的是当前多用户的版本,使 userlist.xml
文件像数据库一样是可以升级的。
guestRestrictions
标签指的是为访客用户设置的权限,可以通过UserManager.setDefaultGuestRestrictions()
来设置。
这里面有两个用户的信息,分别为 id 为 0 和 11
的用户。
得到 Id
信息后还要读取保存了用户注册信息的xml
文件,这个文件也位于/data/system/users
目录下,文件名用用户 Id
数字表示。
0.xml 示例:
11.xml示例:
momxmo
标签的属性值对应了UserInfo
里面的成员变量,读取用户的xml
文件后,会根据文件的内容来创建和初始化一个UserInfo
来保存,UserInfo
作为UserData
的成员变量加入到mUsers
列表中去。
restrictions
表示针对该用户做的权限限制,可以通过UserManager.setUserRestriction()
或UserManager.setUserRestrictions()
进行设置。
如果有未创建完成的用户,即partial=true
的用户,则把它们从用户列表中移除出去。
因此,UMS 的初始化工作主要就是分析userlist.xml
文件、创建用户列表mUsers
以及设置用户权限。
2.3UserInfo
public class UserInfo implements Parcelable {
......
// 用户类型
public static final int FLAG_MASK_USER_TYPE = 0x000000FF;
// 机主用户的标志,通常是第一个ID为0的用户
public static final int FLAG_PRIMARY = 0x00000001;
// 管理员标志,有此标志的才能创建和删除其他用户,通常是机主用户
public static final int FLAG_ADMIN = 0x00000002;
// 访客用户标志
public static final int FLAG_GUEST = 0x00000004;
// 标记权限受限的用户
public static final int FLAG_RESTRICTED = 0x00000008;
// 标记改用户是否进行了初始化
public static final int FLAG_INITIALIZED = 0x00000010;
/**
* Indicates that this user is a profile of another user, for example holding a users
* corporate data.
*/
// 标志该UserInfo是否是另外一个用户的一份profile,Android中允许一个用户拥有另一份profile
// 比如现在好多定制系统开发的应用分身,就是基于这个开发的,比如可以在同一个手机上启动两个微信帐号
public static final int FLAG_MANAGED_PROFILE = 0x00000020;
// 标记该用户已经被禁止
public static final int FLAG_DISABLED = 0x00000040;
// 无效值定义
public static final int NO_PROFILE_GROUP_ID = -1;
public int id; //用户id
public int serialNumber; //用户序列号,唯一的,不会重复
public String name; //用户名称
public String iconPath; //用户头像的路径
public int flags; //用户的标记信息
public long creationTime; //用户创建时间
public long lastLoggedInTime;//用户上次登陆时间
public int profileGroupId; //用户的profile group id
// 用来标记没有创建完成的用户
public boolean partial;
public boolean guestToRemove;
......
}
需要注意的是,用户的Id用来表示用户,如果用户被删除了它的Id会分配给下一个新建的用户,用来保持Id的连续性;
但是serialNumber
是一个不会重复的数字,是不会被重复利用的,用来惟一标识一个用户。
2.4 UserHandle
UserHandle
就代表了设备中的一个用户,提供了一系列针对用户操作的API。
现在先来分析几个用户相关的概念:
-
userId
:用户id -
appId
:是指跟用户无关的应用程序id,取值范围 0 <= appId < 100000 -
uid
:是指跟用户紧密相关的应用程序id
他们之间有一下的换算关系:uid = userId * 100000 + appId
在UserHandle
中有常量PER_USER_RANGE
,它的值为100000
,也就是说每个 user 最大可以有 100000
个 appid 。
下面介绍几个UserHandle的API:
isApp(int uid)
:是否是应用进程
isIsolated(int uid)
:是否是完全隔绝的沙箱进程,完全隔绝的沙箱进程每次启动都是独立的,不能复用已有的进程信息。这个进程与系统其他进程分开且没有自己的权限。
isSameUser(int uid1, int uid2)
:比较两个uid的userId是否相同,即它们是否属于同一个用户
isSameApp(int uid1, int uid2)
:比较两个uid的appId是否相同
getUserId(int uid)
:根据uid获取userId
getAppId(int uid)
:根据uid获取appId
userId的几种类型:
public static final UserHandle OWNER = new UserHandle(USER_OWNER);
public static final UserHandle CURRENT = new UserHandle(USER_CURRENT);
CURRENT
就代表了当前用户的UserHandle
。
2.5 UID
终端输入命令adb shell ps
,可以得到设备的进程信息,下面仅列举部分具有代表性的进程信息:
USER PID PPID VSIZE RSS WCHAN PC NAME
root 1 0 12844 1768 SyS_epoll_ 0000000000 S /init
root 2 0 0 0 kthreadd 0000000000 S kthreadd
root 3 2 0 0 smpboot_th 0000000000 S ksoftirqd/0
root 5 2 0 0 worker_thr 0000000000 S kworker/0:0H
root 7 2 0 0 rcu_gp_kth 0000000000 S rcu_preempt
root 8 2 0 0 rcu_gp_kth 0000000000 S rcu_sched
root 9 2 0 0 rcu_gp_kth 0000000000 S rcu_bh
root 10 2 0 0 smpboot_th 0000000000 S migration/0
root 202 1 14456 1324 SyS_epoll_ 0000000000 S /system/bin/lmkd
system 203 1 14148 1492 binder_thr 0000000000 S /system/bin/servicemanager
system 204 1 159072 10000 SyS_epoll_ 0000000000 S /system/bin/surfaceflinger
system 207 1 13696 1248 poll_sched 0000000000 S /system/bin/6620_launcher
root 209 1 28380 2532 hrtimer_na 0000000000 S /system/bin/netd
root 210 1 12460 1764 poll_sched 0000000000 S /system/bin/debuggerd
root 211 1 15752 1724 poll_sched 0000000000 S /system/bin/debuggerd64
drm 212 1 53596 12036 binder_thr 0000000000 S /system/bin/drmserver
media 213 1 299956 25568 binder_thr 0000000000 S /system/bin/mediaserver
root 214 1 14004 1304 unix_strea 0000000000 S /system/bin/installd
keystore 215 1 18784 2752 binder_thr 0000000000 S /system/bin/keystore
shell 216 1 13164 1336 hrtimer_na 0000000000 S /system/bin/mobile_log_d
shell 217 1 16148 1636 futex_wait 0000000000 S /system/bin/netdiag
root 222 2 0 0 rescuer_th 0000000000 S pvr_workqueue
root 223 2 0 0 rescuer_th 0000000000 S pvr_workqueue
root 224 2 0 0 rescuer_th 0000000000 S pvr_workqueue
gps 225 1 13564 1476 SyS_epoll_ 0000000000 S /system/xbin/mnld
system 559 229 2306532 147320 SyS_epoll_ 0000000000 S system_server
media_rw 686 185 16980 2064 inotify_re 0000000000 S /system/bin/sdcard
u0_a24 716 229 2245132 180428 SyS_epoll_ 0000000000 S com.android.systemui
wifi 1136 1 19712 4228 poll_sched 0000000000 S /system/bin/wpa_supplicant
root 1223 2 0 0 worker_thr 0000000000 S kworker/2:2
shell 9548 9482 13796 1260 __skb_recv 7fb24a54f4 S logcat
u0_a6 9635 229 1605504 71224 SyS_epoll_ 0000000000 S android.process.acore
root 10836 2 0 0 worker_thr 0000000000 S kworker/0:0
root 11438 2 0 0 worker_thr 0000000000 S kworker/0:2
root 11530 2 0 0 worker_thr 0000000000 S kworker/0:1
可以看到 UID 有root,system,shell
等都属于系统 uid,它们定义在在Process.java
文件,如下:
在
Process.java
中还有下面常量:
FIRST_APPLICATION_UID = 10000
LAST_APPLICATION_UID = 19999
FIRST_SHARED_APPLICATION_GID = 50000
LAST_SHARED_APPLICATION_GID = 59999
-
FIRST_ISOLATED_UID = 99000
//沙箱进程起始值 LAST_ISOLATED_UID = 99999
还有像u0_a24
这种uid代表的uid为10024
,代表user 0
的一个应用程序uid,这个转换方法在UserHandle.formatUid()
:
public static void formatUid(StringBuilder sb, int uid) {
if (uid < Process.FIRST_APPLICATION_UID) {
sb.append(uid);
} else {
sb.append('u');
sb.append(getUserId(uid));
final int appId = getAppId(uid);
if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) {
sb.append('i');
sb.append(appId - Process.FIRST_ISOLATED_UID);
} else if (appId >= Process.FIRST_APPLICATION_UID) {
sb.append('a');
sb.append(appId - Process.FIRST_APPLICATION_UID);
} else {
sb.append('s');
sb.append(appId);
}
}
}
如果我们切换到访客模式,还会发现一个UID为u10_a24
的com.android.systemui
进程,因为该应用的appid为10024
,不同的是它们是在不同的用户下面创建的进程。
但是在访客模式下面,root,system,shell
等这些系统进程是和主用户是共用的,不会再创建新的进程。
2.6 UserState
先了解一下用户的几个运行状态:
public final class UserState {
// 用户正在启动
public final static int STATE_BOOTING = 0;
// 用户处于锁定状态。
public final static int STATE_RUNNING_LOCKED = 1;
// 用户处于解锁状态。
public final static int STATE_RUNNING_UNLOCKING = 2;
// 用户处于运行状态。
public final static int STATE_RUNNING_UNLOCKED = 3;
//用户处于被停止的初始过程中。
public final static int STATE_STOPPING = 4;
// 用户处于停止发送的最后阶段Intent.ACTION_SHUTDOWN.
public final static int STATE_SHUTDOWN = 5;
}
UserController.java
有下列变量来存储用户的相关信息:
-
mCurrentUserId
表示当前正在允许的用户的Id; -
mTargetUserId
记录当前正在切换到该用户; -
mStartedUsers
保存了当前已经运行过的用户的列表,这个列表中的用户会有上面的四种状态 -
mUserLru
用最近最少使用算法保存的用户列表,最近的前台用户保存在列表的最后位置 -
mStartedUserArray
表示mStartedUsers中当前正在运行的用户列表的index,即mStartedUsers中除去正在关闭和已经被关闭状态外的用户
三、创建用户
3.1UserManagerService
UMS 中创建用户是在createUser()
方法中实现的:
@Override
public UserInfo createUser(String name, int flags) {
checkManageOrCreateUsersPermission(flags);
return createUserInternal(name, flags, UserHandle.USER_NULL);
}
首先检查调用者的权限,只有 UID 是 system 或者root或者具有android.Manifest.permission.MANAGE_USERS
和 android.Manifest.permission.CREATE_USERS
的应用才有权限,否则抛出异常。然后就调用createUserInternalUnchecked
来执行真正的创建工作。
private UserInfo createUserInternalUnchecked(String name, int flags, int parentId,
String[] disallowedPackages) {
DeviceStorageMonitorInternal dsm = LocalServices
.getService(DeviceStorageMonitorInternal.class);
// 检查系统是否是低内存状态
if (dsm.isMemoryLow()) {
Log.w(LOG_TAG, "Cannot add user. Not enough space on disk.");
return null;
}
// 检查是否是低内存设备
if (ActivityManager.isLowRamDeviceStatic()) {
return null;
}
final boolean isGuest = (flags & UserInfo.FLAG_GUEST) != 0;
final boolean isManagedProfile = (flags & UserInfo.FLAG_MANAGED_PROFILE) != 0;
final boolean isRestricted = (flags & UserInfo.FLAG_RESTRICTED) != 0;
final boolean isDemo = (flags & UserInfo.FLAG_DEMO) != 0;
final long ident = Binder.clearCallingIdentity();
UserInfo userInfo;
UserData userData;
final int userId;
try {
synchronized (mPackagesLock) {
UserData parent = null;
if (parentId != UserHandle.USER_NULL) {
synchronized (mUsersLock) {
parent = getUserDataLU(parentId);
}
if (parent == null) return null;
}
if (isManagedProfile && !canAddMoreManagedProfiles(parentId, false)) {
Log.e(LOG_TAG, "Cannot add more managed profiles for user " + parentId);
return null;
}
//如果我们不添加一个客户/演示用户或一个管理的配置文件,并且有限制已到达,无法添加用户。
if (!isGuest && !isManagedProfile && !isDemo && isUserLimitReached()) {
return null;
}
// 如果添加的是Guest用户,但是系统中已经存在一个,则不允许再添加
if (isGuest && findCurrentGuestUser() != null) {
return null;
}
...............
// In split system user mode, we assign the first human user the primary flag.
// And if there is no device owner, we also assign the admin flag to primary user.
if (UserManager.isSplitSystemUser()
&& !isGuest && !isManagedProfile && getPrimaryUser() == null) {
flags |= UserInfo.FLAG_PRIMARY;
synchronized (mUsersLock) {
if (!mIsDeviceManaged) {
flags |= UserInfo.FLAG_ADMIN;
}
}
}
// 得到新用户的Id
userId = getNextAvailableId();
Environment.getUserSystemDirectory(userId).mkdirs();
boolean ephemeralGuests = Resources.getSystem()
.getBoolean(com.android.internal.R.bool.config_guestUserEphemeral);
synchronized (mUsersLock) {
// Add ephemeral flag to guests/users if required. Also inherit it from parent.
if ((isGuest && ephemeralGuests) || mForceEphemeralUsers
|| (parent != null && parent.info.isEphemeral())) {
flags |= UserInfo.FLAG_EPHEMERAL;
}
// 为该新用户创建UserInfo
userInfo = new UserInfo(userId, name, null, flags);
// 设置序列号
userInfo.serialNumber = mNextSerialNumber++;
// 设置创建时间
long now = System.currentTimeMillis();
userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
userInfo.partial = true;
userInfo.lastLoggedInFingerprint = Build.FINGERPRINT;
if (isManagedProfile && parentId != UserHandle.USER_NULL) {
userInfo.profileBadge = getFreeProfileBadgeLU(parentId);
}
userData = new UserData();
userData.info = userInfo;
// 放入mUsers列表
mUsers.put(userId, userData);
}
// 将用户信息记录在/data/user/userid/userid.xml中
writeUserLP(userData);
// 把创建用户目录,把用户信息写入userlist.xml
writeUserListLP();
if (parent != null) {
if (isManagedProfile) {
if (parent.info.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
parent.info.profileGroupId = parent.info.id;
writeUserLP(parent);
}
userInfo.profileGroupId = parent.info.profileGroupId;
} else if (isRestricted) {
if (parent.info.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID) {
parent.info.restrictedProfileParentId = parent.info.id;
writeUserLP(parent);
}
userInfo.restrictedProfileParentId = parent.info.restrictedProfileParentId;
}
}
}
// 将用户信息存储到StorageManager中
final StorageManager storage = mContext.getSystemService(StorageManager.class);
storage.createUserKey(userId, userInfo.serialNumber, userInfo.isEphemeral());
mUserDataPreparer.prepareUserData(userId, userInfo.serialNumber,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
mPm.createNewUser(userId, disallowedPackages);
userInfo.partial = false;
synchronized (mPackagesLock) {
writeUserLP(userData);
}
updateUserIds();
Bundle restrictions = new Bundle();
if (isGuest) {
synchronized (mGuestRestrictions) {
restrictions.putAll(mGuestRestrictions);
}
}
synchronized (mRestrictionsLock) {
mBaseUserRestrictions.append(userId, restrictions);
}
// 调用PackageManagerService的createNewUserLILPw方法,此方法很重要,后面会单独分析
// 这个函数会在新建用户的userDir目录下面为所有应用创建数据
// 此方法将新用户可以使用的App在/data/user/<用户Id>文件夹下创建数据目录,目录名称为包名
mPm.onNewUserCreated(userId);
// 发送用户创建完成的广播,广播附带用户的id
Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
android.Manifest.permission.MANAGE_USERS);
MetricsLogger.count(mContext, isGuest ? TRON_GUEST_CREATED : TRON_USER_CREATED, 1);
} finally {
Binder.restoreCallingIdentity(ident);
}
return userInfo;
}
由上面的代码可知,createUser
主要做了一下工作:
- 检查调用进程所属用户是否被限制添加用户、当前设备是否是低内存设备、当前用户数是否已达上限,如是则停止创建新用户
- 为新用户设置用户信息,比如Id,序列号创建时间等,并创建用户目录
/data/user//
或者/mnt/expand//user//
- 将用户信息写入userid.xml与userlist.xml,注意,此时的userInfo.partial = true,表示正在创建
- 调用PackageManagerService的
createNewUser
和onNewUserCreated
方法,这个函数会在新建用户的目录下面为所有应用创建数据目录和设置权限 - 创建用户完成,将
userInfo.partial
设置为false
,创建用户的信息文件,比如0.xml
- 发送用户创建完成的广播
3.2PackageManagerService
创建用户数据createNewUser()
/** Called by UserManagerService */
void createNewUser(int userId, String[] disallowedPackages) {
synchronized (mInstallLock) {
// 调用mSettings.createNewUserLILP为新用户中的应用创建应用数据目录
mSettings.createNewUserLI(this, mInstaller, userId, disallowedPackages);
}
synchronized (mPackages) {
scheduleWritePackageRestrictionsLocked(userId);
scheduleWritePackageListLocked(userId);
applyFactoryDefaultBrowserLPw(userId);
primeDomainVerificationsLPw(userId);
}
}
下面来看一下Settings.createNewUserLI()
方法的代码:
frameworks/base/services/core/java/com/android/server/pm/Settings.java
void createNewUserLI(@NonNull PackageManagerService service, @NonNull Installer installer,
int userHandle, String[] disallowedPackages) {
.................
// 为每一个应用创建数据目录
for (int i = 0; i < packagesCount; i++) {
if (names[i] == null) {
continue;
}
// TODO: triage flags!
final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
try {
// 通过mInstaller调用守护进程installd执行mkuserdata,为用户创建用户目录。
installer.createAppData(volumeUuids[i], names[i], userHandle, flags, appIds[i],
seinfos[i], targetSdkVersions[i]);
} catch (InstallerException e) {
Slog.w(TAG, "Failed to prepare app data", e);
}
}
synchronized (mPackages) {
applyDefaultPreferredAppsLPw(service, userHandle);
}
}
对每一个用户,系统都会以 PackageuserState
类来保护其安装的每一个包状态。它以SparseArray
的形式由PackageSetting
类来保护,PackageSetting
存储了每一个安装包的数据。也就是说对于每个安装包,里面都有个每个用户对应的列表 userState
来存储该安装包对于不同用户的不同状态,比如针对该用户是否隐藏以及是否标识为已安装状态。
四、切换用户
ActivityManagerService
startUserInBackground
启动用户,运行在后台。
@Override
public boolean startUserInBackground(final int userId) {
return mUserController.startUser(userId, /* foreground */ false);
}
最终调用UserController
启动;
下面介绍一下切换用户的流程,比如我们从机主用户切换到访客用户是就是走的这个流程。
用户切换是通过调用ActivityManager的public boolean switchUser(int userId)
方法进行。一般通过 ActivityManagerNative.getDefault().switchUser(int userId)
进行调用。
最终会调用ActivityManagerService.switchUser
方法:
@Override
public boolean switchUser(final int targetUserId) {
enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, targetUserId);
int currentUserId;
UserInfo targetUserInfo;
synchronized (this) {
currentUserId = mUserController.getCurrentUserIdLocked();
targetUserInfo = mUserController.getUserInfo(targetUserId);
..........
//判断条件
..............
// 该user只是一个user的profile,无法切换
if (targetUserInfo.isManagedProfile()) {
Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not a full user");
return false;
}
mUserController.setTargetUserIdLocked(targetUserId);
}
// 发送切换用户的消息
mUiHandler.removeMessages(START_USER_SWITCH_UI_MSG);
mUiHandler.sendMessage(mHandler.obtainMessage(
START_USER_SWITCH_UI_MSG, userNames));
return true;
}
Handler
收到START_USER_SWITCH_UI_MSG
消息后,会调用mUserController.showUserSwitchDialo()
来弹出一个确认的对话框。
void showUserSwitchingDialog(UserInfo fromUser, UserInfo toUser) {
Dialog d = new UserSwitchingDialog(mService, mService.mContext, fromUser, toUser,
true /* above system */);
d.show();
}
点击确定后最终会调用到UserController.startUserInForeground()
来执行切换用户的动作。
ActivityManagerService .mUserController.startUserInForeground(mUserId);
/**
* Start user, if its not already running, and bring it to foreground.
*/
void startUserInForeground(final int targetUserId) {
boolean success = startUser(targetUserId, /* foreground */ true);
if (!success) {
mInjector.getWindowManager().setSwitchingUser(false);
}
}
boolean startUser(final int userId, final boolean foreground) {
//切换用话需要INTERACT_ACROSS_USERS_FULL权限
if (mInjector.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
!= PackageManager.PERMISSION_GRANTED) {
........
throw new SecurityException(msg);
}
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
// 如果当前用户已经是需要切换的用户,退出当前流程
final int oldUserId = mCurrentUserId;
if (oldUserId == userId) {
return true;
}
if (foreground) {
mInjector.getActivityStackSupervisor().setLockTaskModeLocked(
null, ActivityManager.LOCK_TASK_MODE_NONE, "startUser", false);
}
// 如果没有需要启动的用户的信息,则直接退出
final UserInfo userInfo = getUserInfo(userId);
if (userInfo == null) {
Slog.w(TAG, "No user info for user #" + userId);
return false;
}
// 如果是前台启动且是一份profile的话,则直接退出
if (foreground && userInfo.isManagedProfile()) {
Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
return false;
}
// 如果是前台启动,则需要将屏幕冻结
if (foreground && mUserSwitchUiEnabled) {
mInjector.getWindowManager().startFreezingScreen(
R.anim.screen_user_exit, R.anim.screen_user_enter);
}
boolean needStart = false;
// 如果当前已经启动过的用户列表中没有该用户,则需要先启动该用户
if (mStartedUsers.get(userId) == null) {
UserState userState = new UserState(UserHandle.of(userId));
mStartedUsers.put(userId, userState);
mInjector.getUserManagerInternal().setUserState(userId, userState.state);
updateStartedUserArrayLocked();
needStart = true;
}
// 调整该用户在mUserLru列表中的位置,当前用户放到最后位置
final UserState uss = mStartedUsers.get(userId);
final Integer userIdInt = userId;
mUserLru.remove(userIdInt);
mUserLru.add(userIdInt);
if (foreground) {
// 如果是前台切换,直接切换到需要启动的用户
mCurrentUserId = userId;
mInjector.updateUserConfigurationLocked();
// 重置mTargetUserId,因为userId已经赋值给mCurrentUserId了
mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up
// 更新与该用户相关的profile列表
updateCurrentProfileIdsLocked();
mInjector.getWindowManager().setCurrentUser(userId, mCurrentProfileIds);
// 一旦活动用户的内部概念切换,我们就锁定设备
// 带有在键控上显示用户切换器的选项。
if (mUserSwitchUiEnabled) {
// 在WindowManagerService中设置切换用户
mInjector.getWindowManager().setSwitchingUser(true);
// 执行锁屏操作
mInjector.getWindowManager().lockNow(null);
}
} else {
// 如果是后台启动
final Integer currentUserIdInt = mCurrentUserId;
// 更新与该用户相关的profile列表
updateCurrentProfileIdsLocked();
mInjector.getWindowManager().setCurrentProfileIds(mCurrentProfileIds);
// 重新调整mUserLru
mUserLru.remove(currentUserIdInt);
mUserLru.add(currentUserIdInt);
}
// Make sure user is in the started state. If it is currently
// stopping, we need to knock that off.
if (uss.state == UserState.STATE_STOPPING) {
// // 如果该用户是正在停止,这个时候还没有发送ACTION_SHUTDOWN广播,则切换为正在运行
..............
} else if (uss.state == UserState.STATE_SHUTDOWN) {
..............
}
if (uss.state == UserState.STATE_BOOTING) {
// 如果用户的状态是正在启动,则发送一个SYSTEM_USER_START_MSG消息,该消息的处理下面会介绍
mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_START_MSG, userId, 0));
}
..............
if (foreground) {
// 设置为前台用户
moveUserToForegroundLocked(uss, oldUserId, userId);
} else {
finishUserBoot(uss);
}
..............
if (foreground) {
// 发送SYSTEM_USER_CURRENT_MSG消息mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_CURRENT_MSG, userId,
oldUserId));
mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,
oldUserId, userId, uss));
mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,
oldUserId, userId, uss), USER_SWITCH_TIMEOUT);
}
if (needStart) {
//广播通知新用户启动
Intent intent = new Intent(Intent.ACTION_USER_STARTING);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
mInjector.broadcastIntentLocked(intent,
null, new IIntentReceiver.Stub() {
@Override
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered, boolean sticky,
int sendingUser) throws RemoteException {
}
}, 0, null, null,
new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
return true;
}
下面来分析一下moveUserToForegroundLocked()
函数
void moveUserToForegroundLocked(UserState uss, int oldUserId, int newUserId) {
//从mStackSupervisor获取newUserId用户在切换之前的stack状态,以便将原来在前台的应用推到前台
boolean homeInFront =
mInjector.getActivityStackSupervisor().switchUserLocked(newUserId, uss);
if (homeInFront) {
// 如果原来是从桌面切换的用户,则启动桌面
mInjector.startHomeActivityLocked(newUserId, "moveUserToForeground");
} else {
// 如果是其他应用,则将此应用推到前台mInjector.getActivityStackSupervisor().resumeFocusedStackTopActivityLocked();
}
EventLogTags.writeAmSwitchUser(newUserId);
// 发送ACTION_USER_BACKGROUND广播,通知和oldUserId相关的用户(包括profile)进入后台的消息
// 发送ACTION_USER_FOREGROUND广播,通知和newUserId相关的用户(包括profile)进入前台的消息
// 发送ACTION_USER_SWITCHED广播,通知用户切换
sendUserSwitchBroadcastsLocked(oldUserId, newUserId);
}
消息处理
下面介绍一下startUser()中发出的几条消息的处理。
ActivityManagerService
中handler.SYSTEM_USER_CURRENT_MSG
:
case SYSTEM_USER_CURRENT_MSG: {
mBatteryStatsService.noteEvent(
BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_FINISH,
Integer.toString(msg.arg2), msg.arg2);
mBatteryStatsService.noteEvent(
BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START,
Integer.toString(msg.arg1), msg.arg1);
mSystemServiceManager.switchUser(msg.arg1);
break;
}
这里主要是通知BatteryStatsServic
e用户切换的消息以及让SystemServiceManager
调用各个SystemService
的onSwitchUser(userHandle)
方法。
更新用户状态,停止旧用户
在Activity
进入Idle状态后会调用AMS的activityIdle()
方法,此方法会调用mStackSupervisor.activityIdleInternalLocked(token, false, config);
,在activityIdleInternalLocked()
方法内有下面的处理:
if (!booting) {
// Complete user switch
if (startingUsers != null) {
for (int i = 0; i < startingUsers.size(); i++) {
mService.mUserController.finishUserSwitch(startingUsers.get(i));
}
}
}
当前有正在切换的用户的话就会调用UserController的finishUserSwitch()
和finishUserBoot()
方法,来更新用户状态,发送广播以及处理需要停止的用户工作。
下面来看一下 UserController的finishUserSwitch()
和finishUserBoot()
方法:
void finishUserSwitch(UserState uss) {
synchronized (mLock) {
finishUserBoot(uss);
startProfilesLocked();
//停止所有旧用户运行
stopRunningUsersLocked(MAX_RUNNING_USERS);
}
}
private void finishUserBoot(UserState uss, IIntentReceiver resultTo) {
......
if (uss.setState(STATE_BOOTING, STATE_RUNNING_LOCKED)) {
mInjector.getUserManagerInternal().setUserState(userId, uss.state);
// Do not report secondary users, runtime restarts or first boot/upgrade
if (userId == UserHandle.USER_SYSTEM
&& !mInjector.isRuntimeRestarted() && !mInjector.isFirstBootOrUpgrade()) {
int uptimeSeconds = (int)(SystemClock.elapsedRealtime() / 1000);
MetricsLogger.histogram(mInjector.getContext(),
"framework_locked_boot_completed", uptimeSeconds);
final int MAX_UPTIME_SECONDS = 120;
if (uptimeSeconds > MAX_UPTIME_SECONDS) {
Slog.wtf("SystemServerTiming",
"finishUserBoot took too long. uptimeSeconds=" + uptimeSeconds);
}
}
mHandler.sendMessage(mHandler.obtainMessage(REPORT_LOCKED_BOOT_COMPLETE_MSG,
userId, 0));
Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mInjector.broadcastIntentLocked(intent, null, resultTo, 0, null, null,
new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED },
AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
}
....
}
通过finishUserSwitch
->finishUserBoot
来将用户的状态置为UserState.STATE_RUNNING_LOCKED
,并发出广播Intent.ACTION_LOCKED_BOOT_COMPLETED
广播。
至此,用户切换工作全部结束。
五、删除用户
UserManagerService
删除为该用户创建的用户和所有数据目录。
UserManagerService
中删除用户是在removeUser()
方法中实现的:
public boolean removeUser(int userHandle) {
.....................
return removeUserUnchecked(userHandle);
}
private boolean removeUserUnchecked(int userHandle) {
.....
//获取当前用户
int currentUser = ActivityManager.getCurrentUser();
........
//获取将要执行删除的用户
userData = mUsers.get(userHandle);
..........
// 将partial设置为true,这样如果后面的过程意外终止导致此次删除失败,系统重启后还是会继续删除工作的
userData.info.partial = true;
//禁用并修改
userData.info.flags |= UserInfo.FLAG_DISABLED;
// 将上面更新的用户文件信息写入到xml文件中去
writeUserLP(userData);
.............
// 调用AMS停止当前的用户,这部分后面会详细介绍
int res;
try {
res = ActivityManager.getService().stopUser(userHandle, /* force= */ true,
// // 设置回调函数,调用finishRemoveUser继续后面的删除工作
new IStopUserCallback.Stub() {
@Override
public void userStopped(int userId) {
finishRemoveUser(userId);
}
@Override
public void userStopAborted(int userId) {
}
});
} catch (RemoteException e) {
return false;
}
}
ActivityManagerNative.getDefault().stopUser
执行完后 UMS 会继续执行删除工作。
void finishRemoveUser(final int userHandle) {
if (DBG) Slog.i(LOG_TAG, "finishRemoveUser " + userHandle);
// Let other services shutdown any activity and clean up their state before completely
// wiping the user's system directory and removing from the user list
long ident = Binder.clearCallingIdentity();
try {
Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
mContext.sendOrderedBroadcastAsUser(addedIntent, UserHandle.ALL,
android.Manifest.permission.MANAGE_USERS,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (DBG) {
Slog.i(LOG_TAG,
"USER_REMOVED broadcast sent, cleaning up user data "
+ userHandle);
}
new Thread() {
@Override
public void run() {
// Clean up any ActivityManager state
LocalServices.getService(ActivityManagerInternal.class)
.onUserRemoved(userHandle);
removeUserState(userHandle);
}
}.start();
}
},
null, Activity.RESULT_OK, null, null);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
根据代码可以看到finishRemoveUser方法
只是发送了一个有序广播ACTION_USER_REMOVED
,同时注册了一个广播接收器,这个广播接收器是最后一个接收到该广播的接收器,这样做的目的是让关心该广播的其他接收器处理完之后, UMS 才会进行删除用户的收尾工作,即调用removeUserState来删除用户的相关文件。
private void removeUserState(final int userHandle) {
try {
//删除StorageManager里面存储的用户
mContext.getSystemService(StorageManager.class).destroyUserKey(userHandle);
} catch (IllegalStateException e) {
.......
}
...........
// 调用mPm.cleanUpUserLILPw来删除用户目录/data/user/<用户id>/下面的应用数据,后面会详细介绍
mPm.cleanUpUser(this, userHandle);
.................................
// 各种删除操作
.................................
// 更新user list xml文件
synchronized (mPackagesLock) {
writeUserListLP();
}
// 删除用户文件
AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX));
userFile.delete();
updateUserIds();
if (RELEASE_DELETED_USER_ID) {
synchronized (mUsers) {
mRemovingUserIds.delete(userHandle);
}
}
}
至此,删除用户的工作已经全部完成。
PackageManagerService
UMS的removeUser()
会调用PMS的cleanUpUser()
删除用户数据;
void cleanUpUser(UserManagerService userManager, int userHandle) {
synchronized (mPackages) {
mDirtyUsers.remove(userHandle);
mUserNeedsBadging.delete(userHandle);
mSettings.removeUserLPw(userHandle);
mPendingBroadcasts.remove(userHandle);
mInstantAppRegistry.onUserRemovedLPw(userHandle);
removeUnusedPackagesLPw(userManager, userHandle);
}
}
删除用户的工作比较简单,删除用户的数据。同时调用mSettings.removeUserLPw(userHandle)
来删除和 PMS 中和用户相关的信息。
void removeUserLPw(int userId) {
// 删除每个应用中的该用户的信息
Set> entries = mPackages.entrySet();
for (Entry entry : entries) {
entry.getValue().removeUser(userId);
}
mPreferredActivities.remove(userId);
File file = getUserPackagesStateFile(userId);
file.delete();
file = getUserPackagesStateBackupFile(userId);
file.delete();
removeCrossProfileIntentFiltersLPw(userId);
mRuntimePermissionsPersistence.onUserRemovedLPw(userId);
// 更新/data/system/packages.list文件
writePackageListLPr();
// 通知内核用户已被删除,以便将包标记为uninstall
对于sdcardfs
writeKernelRemoveUserLPr(userId);
}