Android Multi_User 添加新用户源码分析

来源:互联网 发布:网络传销名单 编辑:程序博客网 时间:2024/05/29 02:46
PackageManagerService

1,首先看UserManager中的createUser函数,他是创建新用户的入口
  1.       public UserInfo createUser(String name, int flags) {
  2.             try {
  3.                 //调用UserManagerService的createUser方法
  4.                 return mService.createUser(name, flags);
  5.             } catch (RemoteException re) {
  6.                 Log.w(TAG, "Could not create a user", re);
  7.                 return null;
  8.             }
  9.         }
复制代码
由上可知,该段代码主要功能就是调用了UserManagerService的对应的createUser函数。

2,下面我们重点分析一下UserManagerService的createUser方法
  1. @Override
  2.     public UserInfo createUser(String name, int flags) {
  3.         //权限检查
  4.         checkManageUsersPermission("Only the system can create users");

  5.         final long ident = Binder.clearCallingIdentity();
  6.         final UserInfo userInfo;
  7.         try {
  8.             synchronized (mInstallLock) {
  9.                 synchronized (mPackagesLock) {
  10.                     //如果当前用户数,已经到达支持数目,则停止创建新用户
  11.                     if (isUserLimitReachedLocked()) return null;
  12.                     //生成用户ID
  13.                     int userId = getNextAvailableIdLocked();
  14.                     //创建一个userInfo实例
  15.                     userInfo = new UserInfo(userId, name, null, flags);
  16.                     //指向“data/user/userId”文件夹
  17.                     File userPath = new File(mBaseUserPath, Integer.toString(userId));
  18.                     //mNextSerialNumber就是UserManagerService的构造函数中读取到的
  19.                     userInfo.serialNumber = mNextSerialNumber++;
  20.                     long now = System.currentTimeMillis();
  21.                     userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
  22.                     //该值为true,表明用户尚未创建成功
  23.                     userInfo.partial = true;
  24.                     //为新用户创建“data/system/users/userId”目录
  25.                     Environment.getUserSystemDirectory(userInfo.id).mkdirs();
  26.                     //将新用户添加到mUsers 中
  27.                     mUsers.put(userId, userInfo);
  28.                     //将新用户信息写入到“data/system/users/userlist.xml”之中
  29.                     writeUserListLocked();
  30.                     //将新用户信息写入到“data/system/users/userId.xml”之中
  31.                     writeUserLocked(userInfo);
  32.                     mPm.createNewUserLILPw(userId, userPath);
  33.                     //新用户创建成功
  34.                     userInfo.partial = false;
  35.                     //更新新用户的partial属性为false,更新“data/system/users/userId.xml”
  36.                     writeUserLocked(userInfo);
  37.                     //更新mUserIds数组
  38.                     updateUserIdsLocked();
  39.                     //这是用户限制“restrictions”相关的内容,将在其他地方讲解
  40.                     Bundle restrictions = new Bundle();
  41.                     mUserRestrictions.append(userId, restrictions);
  42.                 }
  43.             }
  44.             if (userInfo != null) {
  45.                 //发送广播Intent.ACTION_USER_ADDED
  46.                 //同时此广播附带Intent.EXTRA_USER_HANDLE类型的userInfo.id消息,
  47.                 //便于接收到广播的组件读取用户ID
  48.                 Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
  49.                 addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id);
  50.                 mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
  51.                         android.Manifest.permission.MANAGE_USERS);
  52.             }
  53.         } finally {
  54.             Binder.restoreCallingIdentity(ident);
  55.         }
  56.         return userInfo;
  57.     }
复制代码
由上面代码可知,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
 
回复

举报

  
西夏

250

主题

7

好友

1万

积分

超级版主

Rank: 8Rank: 8

  • 发消息
沙发
 发表于 2014-1-16 18:29:03 |只看该作者
3,下面看看writeUserListLocked函数所写的“data/system/users/userlist.xml”的格式
  1. /**
  2.              *   <?xml version="1.0" encoding="utf-8" standalone="yes" ?> 
  3.              *  - <users nextSerialNumber="11" version="2">
  4.              *       <user id="0" /> 
  5.              *       <user id="10" /> 
  6.              *   </users>
  7.              */
复制代码
具体,可自行从你的安卓设备中下载查看。

4,下面再看看writeUserLocked函数所写的“data/system/users/userId.xml”文件的格式
  1. /**
  2.      *  <?xml version="1.0" encoding="utf-8" standalone="yes" ?> 
  3.      * - <user id="11" serialNumber="14" flags="16" created="1388534774982" 
  4.      *     lastLoggedIn="1388534863493" icon="/data/system/users/11/photo.png">
  5.      *      <name>新用户</name> 
  6.      *      <restrictions /> 
  7.      *   </user>
  8.      */
复制代码
5,下面重点分析PackageManagerService的createNewUserLILPw方法
  1.     void createNewUserLILPw(int userHandle, File path) {
  2.         if (mInstaller != null) {
  3.             mSettings.createNewUserLILPw(this, mInstaller, userHandle, path);
  4.         }
  5.     }
复制代码
A,该方法调用了Settings中的createNewUserLILPw方法
  
回复

举报

  
西夏

250

主题

7

好友

1万

积分

超级版主

Rank: 8Rank: 8

  • 发消息
板凳
 发表于 2014-1-16 18:32:17 |只看该作者
6,下面看一下Settings的createNewUserLILPw函数
  1. void createNewUserLILPw(PackageManagerService service, Installer installer,
  2.             int userHandle, File path) {
  3.         //创建“data/user/userId”文件夹
  4.         path.mkdir();
  5.         FileUtils.setPermissions(path.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
  6.                 | FileUtils.S_IXOTH, -1, -1);
  7.         for (PackageSetting ps : mPackages.values()) {
  8.             // Only system apps are initially installed.
  9.             //存放在"system/app"文件夹下的app都属于系统应用
  10.             //他们都具有这样的属性:(ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
  11.             //将所有"system/app"文件夹下的app的PackageUserState的installed属性置为true
  12.             ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle);
  13.             // Need to create a data directory for all apps under this user.
  14.             installer.createUserData(ps.name,
  15.                     UserHandle.getUid(userHandle, ps.appId), userHandle);
  16.         }
  17.         // 从”etc/preferred-apps”目录下的XML文件
  18.         readDefaultPreferredAppsLPw(service, userHandle);
  19.         // 写当前用户的“data/system/users/userId/package-restrictions.xml”文件
  20.         writePackageRestrictionsLPr(userHandle);
  21.     }
复制代码
A,该方法首先将所有“system/app”文件夹下的系统应用的installed属性设置为true
B,然后调用Installer.java中的createUserData函数
C,读取”etc/preferred-apps”目录下的XML文件
D,写入当前用户的“data/system/users/userId/package-restrictions.xml”文件

7,下面我们重点看看writePackageRestrictionsLPr函数,该函数源码如下
  1. void writePackageRestrictionsLPr(int userId) {
  2.         if (DEBUG_MU) {
  3.             Log.i(TAG, "Writing package restrictions for user=" + userId);
  4.         }
  5.         // Keep the old stopped packages around until we know the new ones have
  6.         // been successfully written.
  7.         //指向文件“data/system/users/userId/package-restrictions.xml”
  8.         File userPackagesStateFile = getUserPackagesStateFile(userId);
  9.         //指向文件“data/system/users/userId/package-restrictions-backup.xml”
  10.         File backupFile = getUserPackagesStateBackupFile(userId);
  11.         new File(userPackagesStateFile.getParent()).mkdirs();
  12.         if (userPackagesStateFile.exists()) {
  13.             // Presence of backup settings file indicates that we failed
  14.             // to persist packages earlier. So preserve the older
  15.             // backup for future reference since the current packages
  16.             // might have been corrupted.
  17.             if (!backupFile.exists()) {
  18.                 if (!userPackagesStateFile.renameTo(backupFile)) {
  19.                     Log.wtf(PackageManagerService.TAG, "Unable to backup user packages state file, "
  20.                             + "current changes will be lost at reboot");
  21.                     return;
  22.                 }
  23.             } else {
  24.                 userPackagesStateFile.delete();
  25.                 Slog.w(PackageManagerService.TAG, "Preserving older stopped packages backup");
  26.             }
  27.         }

  28.         try {
  29.             final FileOutputStream fstr = new FileOutputStream(userPackagesStateFile);
  30.             final BufferedOutputStream str = new BufferedOutputStream(fstr);

  31.             final XmlSerializer serializer = new FastXmlSerializer();
  32.             serializer.setOutput(str, "utf-8");
  33.             serializer.startDocument(null, true);
  34.             serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);

  35.             //XML标记:package-restrictions
  36.             serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS);

  37.             for (final PackageSetting pkg : mPackages.values()) {
  38.                 PackageUserState ustate = pkg.readUserState(userId);
  39.                 if (ustate.stopped || ustate.notLaunched || !ustate.installed
  40.                         || ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT
  41.                         || ustate.blocked
  42.                         || (ustate.enabledComponents != null
  43.                                 && ustate.enabledComponents.size() > 0)
  44.                         || (ustate.disabledComponents != null
  45.                                 && ustate.disabledComponents.size() > 0)) {
  46.                     //XML标记:pkg
  47.                     serializer.startTag(null, TAG_PACKAGE);
  48.                     //XML标记:name
  49.                     serializer.attribute(null, ATTR_NAME, pkg.name);
  50.                     if (DEBUG_MU) Log.i(TAG, "  pkg=" + pkg.name + ", state=" + ustate.enabled);

  51.                     if (!ustate.installed) {
  52.                         //XML标记:inst
  53.                         serializer.attribute(null, ATTR_INSTALLED, "false");
  54.                     }
  55.                     if (ustate.stopped) {
  56.                         //XML标记:stopped
  57.                         serializer.attribute(null, ATTR_STOPPED, "true");
  58.                     }
  59.                     if (ustate.notLaunched) {
  60.                         //XML标记:nl
  61.                         serializer.attribute(null, ATTR_NOT_LAUNCHED, "true");
  62.                     }
  63.                     if (ustate.blocked) {
  64.                         //XML标记:
  65.                         serializer.attribute(null, ATTR_BLOCKED, "true");
  66.                     }
  67.                     if (ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
  68.                         //XML标记:enabled
  69.                         serializer.attribute(null, ATTR_ENABLED,
  70.                                 Integer.toString(ustate.enabled));
  71.                         if (ustate.lastDisableAppCaller != null) {
  72.                             //XML标记:enabledCaller
  73.                             serializer.attribute(null, ATTR_ENABLED_CALLER,
  74.                                     ustate.lastDisableAppCaller);
  75.                         }
  76.                     }
  77.                     if (ustate.enabledComponents != null
  78.                             && ustate.enabledComponents.size() > 0) {
  79.                         //XML标记:enabled-components
  80.                         serializer.startTag(null, TAG_ENABLED_COMPONENTS);
  81.                         for (final String name : ustate.enabledComponents) {
  82.                             //XML标记:item
  83.                             serializer.startTag(null, TAG_ITEM);
  84.                             //XML标记:name
  85.                             serializer.attribute(null, ATTR_NAME, name);
  86.                             //XML标记:item
  87.                             serializer.endTag(null, TAG_ITEM);
  88.                         }
  89.                         //XML标记:enabled-components
  90.                         serializer.endTag(null, TAG_ENABLED_COMPONENTS);
  91.                     }
  92.                     if (ustate.disabledComponents != null
  93.                             && ustate.disabledComponents.size() > 0) {
  94.                         //XML标记:disabled-components
  95.                         serializer.startTag(null, TAG_DISABLED_COMPONENTS);
  96.                         for (final String name : ustate.disabledComponents) {
  97.                             serializer.startTag(null, TAG_ITEM);
  98.                             serializer.attribute(null, ATTR_NAME, name);
  99.                             serializer.endTag(null, TAG_ITEM);
  100.                         }
  101.                         serializer.endTag(null, TAG_DISABLED_COMPONENTS);
  102.                     }
  103.                     //XML标记:pkg
  104.                     serializer.endTag(null, TAG_PACKAGE);
  105.                 }
  106.             }

  107.             writePreferredActivitiesLPr(serializer, userId, true);

  108.             serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);

  109.             serializer.endDocument();

  110.             str.flush();
  111.             FileUtils.sync(fstr);
  112.             str.close();

  113.             // New settings successfully written, old ones are no longer
  114.             // needed.
  115.             backupFile.delete();
  116.             FileUtils.setPermissions(userPackagesStateFile.toString(),
  117.                     FileUtils.S_IRUSR|FileUtils.S_IWUSR
  118.                     |FileUtils.S_IRGRP|FileUtils.S_IWGRP,
  119.                     -1, -1);

  120.             // Done, all is good!
  121.             return;
  122.         } catch(java.io.IOException e) {
  123.             Log.wtf(PackageManagerService.TAG,
  124.                     "Unable to write package manager user packages state, "
  125.                     + " current changes will be lost at reboot", e);
  126.         }

  127.         // Clean up partially written files
  128.         if (userPackagesStateFile.exists()) {
  129.             if (!userPackagesStateFile.delete()) {
  130.                 Log.i(PackageManagerService.TAG, "Failed to clean up mangled file: "
  131.                         + mStoppedPackagesFilename);
  132.             }
  133.         }
  134.     }
复制代码
A,该函数主要工作就是写入当前用户的“data/system/users/userId/package-restrictions.xml”
  
回复

举报

  
西夏

250

主题

7

好友

1万

积分

超级版主

Rank: 8Rank: 8

  • 发消息
地板
 发表于 2014-1-16 18:35:18 |只看该作者
8,下面我们看看Installer.java中的createUserData函数
  1.    public int createUserData(String name, int uid, int userId) {
  2.         //发送一个记号为“mkuserdata”的socket通信
  3.         StringBuilder builder = new StringBuilder("mkuserdata");
  4.         builder.append(' ');
  5.         builder.append(name);
  6.         builder.append(' ');
  7.         builder.append(uid);
  8.         builder.append(' ');
  9.         builder.append(userId);
  10.         return execute(builder.toString());
  11.     }
复制代码
A,该方法发送了一个记号为“mkuserdata”的socket通信

9,该通信的接收处理方是一个C文件installd.c,我们看看该文件的源码
  1. struct cmdinfo cmds[] = {
  2.     { "ping",                 0, do_ping },
  3.     { "install",              4, do_install },
  4.     { "dexopt",               3, do_dexopt },
  5.     { "movedex",              2, do_move_dex },
  6.     { "rmdex",                1, do_rm_dex },
  7.     { "remove",               2, do_remove },
  8.     { "rename",               2, do_rename },
  9.     { "fixuid",               3, do_fixuid },
  10.     { "freecache",            1, do_free_cache },
  11.     { "rmcache",              2, do_rm_cache },
  12.     { "getsize",              6, do_get_size },
  13.     { "rmuserdata",           2, do_rm_user_data },
  14.     { "movefiles",            0, do_movefiles },
  15.     { "linklib",              3, do_linklib },
  16.     { "mkuserdata",           3, do_mk_user_data },
  17.     { "rmuser",               1, do_rm_user },
  18. };

  19. static int do_mk_user_data(char **arg, char reply[REPLY_MAX])
  20. {
  21.     return make_user_data(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, userid */
  22. }
复制代码
A,该文件定义了若干socket通信命令的处理函数
B,由上我们可知,是调用了installd.c中的do_mk_user_data这个函数,而在这个函数中则调用了commands.c中的make_user_data函数
  
回复

举报

  
西夏

250

主题

7

好友

1万

积分

超级版主

Rank: 8Rank: 8

  • 发消息
5#
 发表于 2014-1-16 18:38:15 |只看该作者
10,我们接着看看commands.c中的make_user_data函数源码
  1. int make_user_data(const char *pkgname, uid_t uid, userid_t userid)
  2. {
  3.         //形如"data/user/userId/包名"的路径
  4.     char pkgdir[PKG_PATH_MAX];
  5.     //形如"data/app-lib"的路径
  6.     char applibdir[PKG_PATH_MAX];
  7.     //形如"data/user/userId/包名/lib"的路径
  8.     char libsymlink[PKG_PATH_MAX];
  9.     struct stat libStat;

  10.     // Create the data dir for the package
  11.     //PKG_DIR_POSTFIX 定义是空
  12.     //#define PKG_DIR_POSTFIX        ""
  13.     if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid)) {
  14.         return -1;
  15.     }
  16.     //#define PKG_LIB_POSTFIX        "/lib"
  17.     if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, userid)) {
  18.         ALOGE("cannot create package lib symlink origin path\n");
  19.         return -1;
  20.     }
  21.     //形如"data/app-lib"的路径
  22.     if (create_pkg_path_in_dir(applibdir, &android_app_lib_dir, pkgname, PKG_DIR_POSTFIX)) {
  23.         ALOGE("cannot create package lib symlink dest path\n");
  24.         return -1;
  25.     }

  26.     //创建新的文件夹,权限-rwxr-x--x
  27.     if (mkdir(pkgdir, 0751) < 0) {
  28.         ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
  29.         return -errno;
  30.     }
  31.     //将新的文件夹权限设置为-rwxr-x--x
  32.     if (chmod(pkgdir, 0751) < 0) {
  33.         ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
  34.         unlink(pkgdir);
  35.         return -errno;
  36.     }

  37.     if (lstat(libsymlink, &libStat) < 0) {
  38.         if (errno != ENOENT) {
  39.             ALOGE("couldn't stat lib dir for non-primary: %s\n", strerror(errno));
  40.             unlink(pkgdir);
  41.             return -1;
  42.         }
  43.     } else {
  44.         if (S_ISDIR(libStat.st_mode)) {
  45.             if (delete_dir_contents(libsymlink, 1, 0) < 0) {
  46.                 ALOGE("couldn't delete lib directory during install for non-primary: %s",
  47.                         libsymlink);
  48.                 unlink(pkgdir);
  49.                 return -1;
  50.             }
  51.         } else if (S_ISLNK(libStat.st_mode)) {
  52.             if (unlink(libsymlink) < 0) {
  53.                 ALOGE("couldn't unlink lib directory during install for non-primary: %s",
  54.                         libsymlink);
  55.                 unlink(pkgdir);
  56.                 return -1;
  57.             }
  58.         }
  59.     }

  60.     //让新用户的App中的lib文件指向"data/app-lib"文件中的lib
  61.     if (symlink(applibdir, libsymlink) < 0) {
  62.         ALOGE("couldn't symlink directory for non-primary '%s' -> '%s': %s\n", libsymlink,
  63.                 applibdir, strerror(errno));
  64.         unlink(pkgdir);
  65.         return -1;
  66.     }

  67.     if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
  68.         ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
  69.         unlink(libsymlink);
  70.         unlink(pkgdir);
  71.         return -errno;
  72.     }

  73.     if (chown(pkgdir, uid, uid) < 0) {
  74.         ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
  75.         unlink(libsymlink);
  76.         unlink(pkgdir);
  77.         return -errno;
  78.     }

  79.     return 0;
  80. }
复制代码
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
原创粉丝点击