Android多用户之UserManagerService源码分析

Android可以支持多个用户使用系统,通常第一个在系统中注册的用户将默认成为系统管理员。
不同用户的设置各不相同,并且不同用户安装的应用及应用数据也不相同。但是系统中和硬件相关的设置则是共用的,如网络设置等。

用户切换后前面用户运行的后台进程还可以继续运行,这样进行用户切换时无须中断一些后台进行的耗时操作(如下载)。

管理用户的系统服务--UserManagerService

UserManagerService的主要功能是创建和删除用户,以及查询用户信息。
1.在PackageManagerService中进行初始化

final ArrayMap<String, PackageParser.Package> mPackages =
            new ArrayMap<String, PackageParser.Package>();

public PackageManagerService(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {
	...
    synchronized (mInstallLock) {
        // writer
        synchronized (mPackages) {
			...
            sUserManager = new UserManagerService(context, this, mPackages);
			...
        } // synchronized (mPackages)
    } // synchronized (mInstallLock)
	...
}

@Override
public void systemReady() {
	...
	sUserManager.systemReady();
	...
}

UserManagerService的构造方法如下:

UserManagerService(Context context, PackageManagerService pm, Object packagesLock) {
    this(context, pm, packagesLock, Environment.getDataDirectory());
}

调用了另一个构造方法,并多传递了一个参数:/data目录

private static final String USER_INFO_DIR = "system" + File.separator + "users";

private UserManagerService(Context context, PackageManagerService pm,
        Object packagesLock, File dataDir) {
    mContext = context;
    mPm = pm;
    mPackagesLock = packagesLock;
    mHandler = new MainHandler();
    synchronized (mPackagesLock) {
	// /data/system/users
        mUsersDir = new File(dataDir, USER_INFO_DIR);
        mUsersDir.mkdirs();
        // Make zeroth user directory, for services to migrate their files to that location
        File userZeroDir = new File(mUsersDir, String.valueOf(UserHandle.USER_SYSTEM));
	// 创建第一个用户目录:/data/system/users/0
        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);
	// 初始化来宾账户的默认限制条件
        initDefaultGuestRestrictions();
	// 从/data/system/users/userlist.xml文件读取用户信息
        readUserListLP();
        sInstance = this;
    }
    mLocalService = new LocalService();
    LocalServices.addService(UserManagerInternal.class, mLocalService);
    mLockPatternUtils = new LockPatternUtils(mContext);
    mUserStates.put(UserHandle.USER_SYSTEM, UserState.STATE_BOOTING);
}

private final Bundle mGuestRestrictions = new Bundle();

// 初始化来宾账户的默认限制条件
private void initDefaultGuestRestrictions() {
    synchronized (mGuestRestrictions) {
        if (mGuestRestrictions.isEmpty()) {
	    // "no_config_wifi",不允许配置WiFi
            mGuestRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_WIFI, true);
	    // "no_install_unknown_sources",不允许安装未知来源的应用
            mGuestRestrictions.putBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
	    // "no_outgoing_calls",不允许呼叫电话
            mGuestRestrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, true);
	    // "no_sms",不允许收发短信
            mGuestRestrictions.putBoolean(UserManager.DISALLOW_SMS, true);
        }
    }
}

先看下/data/system/users/userlist.xml文件的内容,再分析读取过程,文件内容如下:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<users nextSerialNumber="10" version="5">
    <guestRestrictions>
        <restrictions no_config_wifi="true" no_outgoing_calls="true" no_sms="true" />
    </guestRestrictions>
    <user id="0" />
</users>

// 从/data/system/users/userlist.xml文件读取用户信息
private final SparseArray<UserData> mUsers = new SparseArray<>();

private void readUserListLP() {
    // 如果文件不存在,则创建管理员用户并返回
    if (!mUserListFile.exists()) {
        fallbackToSingleUserLP();
        return;
    }
    FileInputStream fis = null;
    AtomicFile userListFile = new AtomicFile(mUserListFile);
    try {
        fis = userListFile.openRead();
        XmlPullParser parser = Xml.newPullParser();
        parser.setInput(fis, StandardCharsets.UTF_8.name());
        int type;
        while ((type = parser.next()) != XmlPullParser.START_TAG
                && type != XmlPullParser.END_DOCUMENT) {
            // Skip
        }

        if (type != XmlPullParser.START_TAG) {
            Slog.e(LOG_TAG, "Unable to read user list");
	    // 如果文件异常,则创建管理员用户并返回
            fallbackToSingleUserLP();
            return;
        }

        mNextSerialNumber = -1;
	// 解析文件
        if (parser.getName().equals(TAG_USERS)) {
            String lastSerialNumber = parser.getAttributeValue(null, ATTR_NEXT_SERIAL_NO);
            if (lastSerialNumber != null) {
                mNextSerialNumber = Integer.parseInt(lastSerialNumber);
            }
            String versionNumber = parser.getAttributeValue(null, ATTR_USER_VERSION);
            if (versionNumber != null) {
                mUserVersion = Integer.parseInt(versionNumber);
            }
        }

        final Bundle newDevicePolicyGlobalUserRestrictions = new Bundle();

        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
            if (type == XmlPullParser.START_TAG) {
                final String name = parser.getName();
                if (name.equals(TAG_USER)) {
                    String id = parser.getAttributeValue(null, ATTR_ID);

		    // 初始化UserData对象保存从 /data/system/users/${id}.xml 文件中读取到的用户信息
                    UserData userData = readUserLP(Integer.parseInt(id));

                    if (userData != null) {
                        synchronized (mUsersLock) {
			    // 把解析到的用户信息保存到mUsers中
                            mUsers.put(userData.info.id, userData);
                            if (mNextSerialNumber < 0
                                    || mNextSerialNumber <= userData.info.id) {
                                mNextSerialNumber = userData.info.id + 1;
                            }
                        }
                    }
                } else if (name.equals(TAG_GUEST_RESTRICTIONS)) {
                    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                            && type != XmlPullParser.END_TAG) {
                        if (type == XmlPullParser.START_TAG) {
                            if (parser.getName().equals(TAG_RESTRICTIONS)) {
                                synchronized (mGuestRestrictions) {
                                    UserRestrictionsUtils
                                            .readRestrictions(parser, mGuestRestrictions);
                                }
                            } else if (parser.getName().equals(TAG_DEVICE_POLICY_RESTRICTIONS)
                                    ) {
                                UserRestrictionsUtils.readRestrictions(parser,
                                        newDevicePolicyGlobalUserRestrictions);
                            }
                            break;
                        }
                    }
                } else if (name.equals(TAG_GLOBAL_RESTRICTION_OWNER_ID)) {
                    String ownerUserId = parser.getAttributeValue(null, ATTR_ID);
                    if (ownerUserId != null) {
                        mGlobalRestrictionOwnerUserId = Integer.parseInt(ownerUserId);
                    }
                }
            }
        }
        synchronized (mRestrictionsLock) {
            mDevicePolicyGlobalUserRestrictions = newDevicePolicyGlobalUserRestrictions;
        }
	// 解析完文件后,更新用户ID
        updateUserIds();
	// 如果有必要,则升级Version
        upgradeIfNecessaryLP();
    } catch (IOException | XmlPullParserException e) {
        fallbackToSingleUserLP();
    } finally {
        IoUtils.closeQuietly(fis);
    }
}

// 创建管理员用户
private void fallbackToSingleUserLP() {
    int flags = UserInfo.FLAG_INITIALIZED;
    // In split system user mode, the admin and primary flags are assigned to the first human
    // user.
    if (!UserManager.isSplitSystemUser()) {
        flags |= UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY;
    }
    // Create the system user
    UserInfo system = new UserInfo(UserHandle.USER_SYSTEM, null, null, flags);
    UserData userData = new UserData();
    userData.info = system;
    synchronized (mUsersLock) {
        mUsers.put(system.id, userData);
    }
    mNextSerialNumber = MIN_USER_ID;
    mUserVersion = USER_VERSION;

    Bundle restrictions = new Bundle();
    synchronized (mRestrictionsLock) {
        mBaseUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions);
    }

    // 更新用户ID
    updateUserIds();
    // 初始化来宾账户的默认限制条件
    initDefaultGuestRestrictions();

    /*
     * 把用户信息写到 /data/system/users/${id}.xml文件中,简单的写文件,不再看源码
     * Writes the user file in this format:
     *
     * <user flags="20039023" id="0">
     *   <name>Primary</name>
     * </user>
     */
    writeUserLP(userData);
    /*
     * 把用户信息写到 /data/system/users/userlist.xml文件中
     * Writes the user list file in this format:
     *
     * <users nextSerialNumber="3">
     *   <user id="0"></user>
     *   <user id="2"></user>
     * </users>
     */
    writeUserListLP();
}

这样UserManagerService的初始化工作就完成了,主要的工作就是解析userlist.xml文件,并创建了mUsers列表中的UserData对象。

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值