Android Multi_User 添加新用户源码分析
来源:互联网 发布:网络传销名单 编辑:程序博客网 时间:2024/05/29 02:46
PackageManagerService
1,首先看UserManager中的createUser函数,他是创建新用户的入口- public UserInfo createUser(String name, int flags) {
- try {
- //调用UserManagerService的createUser方法
- return mService.createUser(name, flags);
- } catch (RemoteException re) {
- Log.w(TAG, "Could not create a user", re);
- return null;
- }
- }
复制代码 由上可知,该段代码主要功能就是调用了UserManagerService的对应的createUser函数。
2,下面我们重点分析一下UserManagerService的createUser方法- @Override
- public UserInfo createUser(String name, int flags) {
- //权限检查
- checkManageUsersPermission("Only the system can create users");
- final long ident = Binder.clearCallingIdentity();
- final UserInfo userInfo;
- try {
- synchronized (mInstallLock) {
- synchronized (mPackagesLock) {
- //如果当前用户数,已经到达支持数目,则停止创建新用户
- if (isUserLimitReachedLocked()) return null;
- //生成用户ID
- int userId = getNextAvailableIdLocked();
- //创建一个userInfo实例
- userInfo = new UserInfo(userId, name, null, flags);
- //指向“data/user/userId”文件夹
- File userPath = new File(mBaseUserPath, Integer.toString(userId));
- //mNextSerialNumber就是UserManagerService的构造函数中读取到的
- userInfo.serialNumber = mNextSerialNumber++;
- long now = System.currentTimeMillis();
- userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
- //该值为true,表明用户尚未创建成功
- userInfo.partial = true;
- //为新用户创建“data/system/users/userId”目录
- Environment.getUserSystemDirectory(userInfo.id).mkdirs();
- //将新用户添加到mUsers 中
- mUsers.put(userId, userInfo);
- //将新用户信息写入到“data/system/users/userlist.xml”之中
- writeUserListLocked();
- //将新用户信息写入到“data/system/users/userId.xml”之中
- writeUserLocked(userInfo);
- mPm.createNewUserLILPw(userId, userPath);
- //新用户创建成功
- userInfo.partial = false;
- //更新新用户的partial属性为false,更新“data/system/users/userId.xml”
- writeUserLocked(userInfo);
- //更新mUserIds数组
- updateUserIdsLocked();
- //这是用户限制“restrictions”相关的内容,将在其他地方讲解
- Bundle restrictions = new Bundle();
- mUserRestrictions.append(userId, restrictions);
- }
- }
- if (userInfo != null) {
- //发送广播Intent.ACTION_USER_ADDED
- //同时此广播附带Intent.EXTRA_USER_HANDLE类型的userInfo.id消息,
- //便于接收到广播的组件读取用户ID
- Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
- addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id);
- mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
- android.Manifest.permission.MANAGE_USERS);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- return userInfo;
- }
复制代码 由上面代码可知,UserManagerService的createUser方法主要工作如下:
A,检查当前用户数是否已达上限,如是则停止创建新用户
B,创建新用户userInfo
C,准备创建“data/user/userId”文件夹
D,为新用户创建“data/system/users/userId”文件夹
E,将新用户信息写入到“data/system/users/userlist.xml”文件中
F,将新用户信息写入到“data/system/users/userId.xml”文件之中
G,调用PackageManagerService的createNewUserLILPw,此方法很重要,将在后面重点讲解。此方法首先创建“data/user/userId”文件夹,然后将新用户可以使用的App从“system/app”等地方的APP复制一份到“data/user/userId”文件夹下
H,用户正式创建成功,userInfo.partial值为false,更新“data/system/users/userId.xml”
I,发送Intent.ACTION_USER_ADDED广播,附带了新用户的userId收藏0 沙发 发表于 2014-1-16 18:29:03 |只看该作者
3,下面看看writeUserListLocked函数所写的“data/system/users/userlist.xml”的格式- /**
- * <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
- * - <users nextSerialNumber="11" version="2">
- * <user id="0" />
- * <user id="10" />
- * </users>
- */
复制代码 具体,可自行从你的安卓设备中下载查看。
4,下面再看看writeUserLocked函数所写的“data/system/users/userId.xml”文件的格式- /**
- * <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
- * - <user id="11" serialNumber="14" flags="16" created="1388534774982"
- * lastLoggedIn="1388534863493" icon="/data/system/users/11/photo.png">
- * <name>新用户</name>
- * <restrictions />
- * </user>
- */
复制代码 5,下面重点分析PackageManagerService的createNewUserLILPw方法- void createNewUserLILPw(int userHandle, File path) {
- if (mInstaller != null) {
- mSettings.createNewUserLILPw(this, mInstaller, userHandle, path);
- }
- }
复制代码 A,该方法调用了Settings中的createNewUserLILPw方法 板凳 发表于 2014-1-16 18:32:17 |只看该作者
6,下面看一下Settings的createNewUserLILPw函数- void createNewUserLILPw(PackageManagerService service, Installer installer,
- int userHandle, File path) {
- //创建“data/user/userId”文件夹
- path.mkdir();
- FileUtils.setPermissions(path.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
- | FileUtils.S_IXOTH, -1, -1);
- for (PackageSetting ps : mPackages.values()) {
- // Only system apps are initially installed.
- //存放在"system/app"文件夹下的app都属于系统应用
- //他们都具有这样的属性:(ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
- //将所有"system/app"文件夹下的app的PackageUserState的installed属性置为true
- ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle);
- // Need to create a data directory for all apps under this user.
- installer.createUserData(ps.name,
- UserHandle.getUid(userHandle, ps.appId), userHandle);
- }
- // 从”etc/preferred-apps”目录下的XML文件
- readDefaultPreferredAppsLPw(service, userHandle);
- // 写当前用户的“data/system/users/userId/package-restrictions.xml”文件
- writePackageRestrictionsLPr(userHandle);
- }
复制代码 A,该方法首先将所有“system/app”文件夹下的系统应用的installed属性设置为true
B,然后调用Installer.java中的createUserData函数
C,读取”etc/preferred-apps”目录下的XML文件
D,写入当前用户的“data/system/users/userId/package-restrictions.xml”文件
7,下面我们重点看看writePackageRestrictionsLPr函数,该函数源码如下- void writePackageRestrictionsLPr(int userId) {
- if (DEBUG_MU) {
- Log.i(TAG, "Writing package restrictions for user=" + userId);
- }
- // Keep the old stopped packages around until we know the new ones have
- // been successfully written.
- //指向文件“data/system/users/userId/package-restrictions.xml”
- File userPackagesStateFile = getUserPackagesStateFile(userId);
- //指向文件“data/system/users/userId/package-restrictions-backup.xml”
- File backupFile = getUserPackagesStateBackupFile(userId);
- new File(userPackagesStateFile.getParent()).mkdirs();
- if (userPackagesStateFile.exists()) {
- // Presence of backup settings file indicates that we failed
- // to persist packages earlier. So preserve the older
- // backup for future reference since the current packages
- // might have been corrupted.
- if (!backupFile.exists()) {
- if (!userPackagesStateFile.renameTo(backupFile)) {
- Log.wtf(PackageManagerService.TAG, "Unable to backup user packages state file, "
- + "current changes will be lost at reboot");
- return;
- }
- } else {
- userPackagesStateFile.delete();
- Slog.w(PackageManagerService.TAG, "Preserving older stopped packages backup");
- }
- }
- try {
- final FileOutputStream fstr = new FileOutputStream(userPackagesStateFile);
- final BufferedOutputStream str = new BufferedOutputStream(fstr);
- final XmlSerializer serializer = new FastXmlSerializer();
- serializer.setOutput(str, "utf-8");
- serializer.startDocument(null, true);
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
- //XML标记:package-restrictions
- serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS);
- for (final PackageSetting pkg : mPackages.values()) {
- PackageUserState ustate = pkg.readUserState(userId);
- if (ustate.stopped || ustate.notLaunched || !ustate.installed
- || ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT
- || ustate.blocked
- || (ustate.enabledComponents != null
- && ustate.enabledComponents.size() > 0)
- || (ustate.disabledComponents != null
- && ustate.disabledComponents.size() > 0)) {
- //XML标记:pkg
- serializer.startTag(null, TAG_PACKAGE);
- //XML标记:name
- serializer.attribute(null, ATTR_NAME, pkg.name);
- if (DEBUG_MU) Log.i(TAG, " pkg=" + pkg.name + ", state=" + ustate.enabled);
- if (!ustate.installed) {
- //XML标记:inst
- serializer.attribute(null, ATTR_INSTALLED, "false");
- }
- if (ustate.stopped) {
- //XML标记:stopped
- serializer.attribute(null, ATTR_STOPPED, "true");
- }
- if (ustate.notLaunched) {
- //XML标记:nl
- serializer.attribute(null, ATTR_NOT_LAUNCHED, "true");
- }
- if (ustate.blocked) {
- //XML标记:
- serializer.attribute(null, ATTR_BLOCKED, "true");
- }
- if (ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
- //XML标记:enabled
- serializer.attribute(null, ATTR_ENABLED,
- Integer.toString(ustate.enabled));
- if (ustate.lastDisableAppCaller != null) {
- //XML标记:enabledCaller
- serializer.attribute(null, ATTR_ENABLED_CALLER,
- ustate.lastDisableAppCaller);
- }
- }
- if (ustate.enabledComponents != null
- && ustate.enabledComponents.size() > 0) {
- //XML标记:enabled-components
- serializer.startTag(null, TAG_ENABLED_COMPONENTS);
- for (final String name : ustate.enabledComponents) {
- //XML标记:item
- serializer.startTag(null, TAG_ITEM);
- //XML标记:name
- serializer.attribute(null, ATTR_NAME, name);
- //XML标记:item
- serializer.endTag(null, TAG_ITEM);
- }
- //XML标记:enabled-components
- serializer.endTag(null, TAG_ENABLED_COMPONENTS);
- }
- if (ustate.disabledComponents != null
- && ustate.disabledComponents.size() > 0) {
- //XML标记:disabled-components
- serializer.startTag(null, TAG_DISABLED_COMPONENTS);
- for (final String name : ustate.disabledComponents) {
- serializer.startTag(null, TAG_ITEM);
- serializer.attribute(null, ATTR_NAME, name);
- serializer.endTag(null, TAG_ITEM);
- }
- serializer.endTag(null, TAG_DISABLED_COMPONENTS);
- }
- //XML标记:pkg
- serializer.endTag(null, TAG_PACKAGE);
- }
- }
- writePreferredActivitiesLPr(serializer, userId, true);
- serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
- serializer.endDocument();
- str.flush();
- FileUtils.sync(fstr);
- str.close();
- // New settings successfully written, old ones are no longer
- // needed.
- backupFile.delete();
- FileUtils.setPermissions(userPackagesStateFile.toString(),
- FileUtils.S_IRUSR|FileUtils.S_IWUSR
- |FileUtils.S_IRGRP|FileUtils.S_IWGRP,
- -1, -1);
- // Done, all is good!
- return;
- } catch(java.io.IOException e) {
- Log.wtf(PackageManagerService.TAG,
- "Unable to write package manager user packages state, "
- + " current changes will be lost at reboot", e);
- }
- // Clean up partially written files
- if (userPackagesStateFile.exists()) {
- if (!userPackagesStateFile.delete()) {
- Log.i(PackageManagerService.TAG, "Failed to clean up mangled file: "
- + mStoppedPackagesFilename);
- }
- }
- }
复制代码 A,该函数主要工作就是写入当前用户的“data/system/users/userId/package-restrictions.xml” 地板 发表于 2014-1-16 18:35:18 |只看该作者
8,下面我们看看Installer.java中的createUserData函数- public int createUserData(String name, int uid, int userId) {
- //发送一个记号为“mkuserdata”的socket通信
- StringBuilder builder = new StringBuilder("mkuserdata");
- builder.append(' ');
- builder.append(name);
- builder.append(' ');
- builder.append(uid);
- builder.append(' ');
- builder.append(userId);
- return execute(builder.toString());
- }
复制代码 A,该方法发送了一个记号为“mkuserdata”的socket通信
9,该通信的接收处理方是一个C文件installd.c,我们看看该文件的源码- struct cmdinfo cmds[] = {
- { "ping", 0, do_ping },
- { "install", 4, do_install },
- { "dexopt", 3, do_dexopt },
- { "movedex", 2, do_move_dex },
- { "rmdex", 1, do_rm_dex },
- { "remove", 2, do_remove },
- { "rename", 2, do_rename },
- { "fixuid", 3, do_fixuid },
- { "freecache", 1, do_free_cache },
- { "rmcache", 2, do_rm_cache },
- { "getsize", 6, do_get_size },
- { "rmuserdata", 2, do_rm_user_data },
- { "movefiles", 0, do_movefiles },
- { "linklib", 3, do_linklib },
- { "mkuserdata", 3, do_mk_user_data },
- { "rmuser", 1, do_rm_user },
- };
- static int do_mk_user_data(char **arg, char reply[REPLY_MAX])
- {
- return make_user_data(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, userid */
- }
复制代码 A,该文件定义了若干socket通信命令的处理函数
B,由上我们可知,是调用了installd.c中的do_mk_user_data这个函数,而在这个函数中则调用了commands.c中的make_user_data函数 5# 发表于 2014-1-16 18:38:15 |只看该作者
10,我们接着看看commands.c中的make_user_data函数源码- int make_user_data(const char *pkgname, uid_t uid, userid_t userid)
- {
- //形如"data/user/userId/包名"的路径
- char pkgdir[PKG_PATH_MAX];
- //形如"data/app-lib"的路径
- char applibdir[PKG_PATH_MAX];
- //形如"data/user/userId/包名/lib"的路径
- char libsymlink[PKG_PATH_MAX];
- struct stat libStat;
- // Create the data dir for the package
- //PKG_DIR_POSTFIX 定义是空
- //#define PKG_DIR_POSTFIX ""
- if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid)) {
- return -1;
- }
- //#define PKG_LIB_POSTFIX "/lib"
- if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, userid)) {
- ALOGE("cannot create package lib symlink origin path\n");
- return -1;
- }
- //形如"data/app-lib"的路径
- if (create_pkg_path_in_dir(applibdir, &android_app_lib_dir, pkgname, PKG_DIR_POSTFIX)) {
- ALOGE("cannot create package lib symlink dest path\n");
- return -1;
- }
- //创建新的文件夹,权限-rwxr-x--x
- if (mkdir(pkgdir, 0751) < 0) {
- ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
- return -errno;
- }
- //将新的文件夹权限设置为-rwxr-x--x
- if (chmod(pkgdir, 0751) < 0) {
- ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
- unlink(pkgdir);
- return -errno;
- }
- if (lstat(libsymlink, &libStat) < 0) {
- if (errno != ENOENT) {
- ALOGE("couldn't stat lib dir for non-primary: %s\n", strerror(errno));
- unlink(pkgdir);
- return -1;
- }
- } else {
- if (S_ISDIR(libStat.st_mode)) {
- if (delete_dir_contents(libsymlink, 1, 0) < 0) {
- ALOGE("couldn't delete lib directory during install for non-primary: %s",
- libsymlink);
- unlink(pkgdir);
- return -1;
- }
- } else if (S_ISLNK(libStat.st_mode)) {
- if (unlink(libsymlink) < 0) {
- ALOGE("couldn't unlink lib directory during install for non-primary: %s",
- libsymlink);
- unlink(pkgdir);
- return -1;
- }
- }
- }
- //让新用户的App中的lib文件指向"data/app-lib"文件中的lib
- if (symlink(applibdir, libsymlink) < 0) {
- ALOGE("couldn't symlink directory for non-primary '%s' -> '%s': %s\n", libsymlink,
- applibdir, strerror(errno));
- unlink(pkgdir);
- return -1;
- }
- if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
- ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
- unlink(libsymlink);
- unlink(pkgdir);
- return -errno;
- }
- if (chown(pkgdir, uid, uid) < 0) {
- ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
- unlink(libsymlink);
- unlink(pkgdir);
- return -errno;
- }
- return 0;
- }
复制代码 A,该函数中首先创建形如"data/user/userId/包名"的路径
B,然后创建形如"data/user/userId/包名/lib"的路径
C,在data/app-lib目录下创建相应目录
D,设置"data/user/userId/包名"目录的权限是0751,-rwxr-x--x
E,让新用户的"data/user/userId/包名/lib"文件指向"data/app-lib"文件中的lib 0 0