【源码剖析2】framework 源码 2——UserManagerService之多用户的创建createUser详解

上文提到创建用户的方法:

UserManager mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);

UserInfo  newUserInfo = mUserManager.createUser(“用户名”, 0);

 

入口代码是UserManagerService中的createUser。

public UserInfo createUser(String name, int flags) {

checkManageOrCreateUsersPermission(flags);

return createUserInternal(name, flags, UserHandle.USER_NULL);

}

 

而最核心的方法是createUserInternalUnchecked

 

调用流程实际从UserManager的对外接口代码开始。

APP创建用户,包括系统设置,必须通过UserManager来创建

上文提到了一个示例,而实际上在UserManager中创建用户的代码,一共有六个接口。

 

//1.标准的用户创建

 public UserInfo createUser(String name, int flags) {

        UserInfo user = null;

        try {

            // 核心代码就调用service的createUser。

            user = mService.createUser(name, flags);

            

            if (user != null && !user.isAdmin() && !user.isDemo()) {

                mService.setUserRestriction(DISALLOW_SMS, true, user.id);

                mService.setUserRestriction(DISALLOW_OUTGOING_CALLS, true, user.id);

            }

        } catch (RemoteException re) {

            throw re.rethrowFromSystemServer();

        }

        return user;

    }

 

//2.创建访客用户

public UserInfo createGuest(Context context, String name) {

        UserInfo guest = null;

        try {       

            //同样适用了标准创建方式,只是帮助大家写好了flag,表示创建的是访客。

            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;

    }

 

接下来出现了一个新的创建用户的方法,叫做创建用户的子用户。当创建子用户之后,我总结了一些概念来帮助理解子用户:

a.用户和其子用户成对出现,user是正常用户,profile是子用户

b.profile必须依附于user生存,也就是一个子用户一定对应一个主用户。

c.当一个用户创建了子用户之后,该用户和子用户直接就建立了连接。我们这时候可以称这个用户为主用户。也就是主用户和子用户的成对出现的概率。

d.感觉有人读到这里有点绕,这是因为代码里面User的概念太宽泛:我们通过UserId来区分每个用户,而仅仅拥有UserId的情况下,我们无法知道这个UserId对应的User是普通用户,还是具备子用户的主用户,或者就是子用户。在代码里面,所用用户无论子用户,主用户,乃至工作用户,统统都是User。

d.对于一个用户我们通过getprofiles方法,可以获取该用户及其关联用户的userId。 也就是普通用户会获取一个user,而无论是主用户还是子用户,都会获取出主用户+子用户的user集合。

e.对于一个子用户而言,它的parentUser是主用户。对于主用户而言,它的profile是子用户。

  总结在创建的时候,我们可以知道我们是创建子用户。但是对于某个用户而言,我们需要对其参数进行判断才能知道其为哪种类型的用户。

 

在创建子用户的时候,需要传入正常用户的信息。

 

//3。创建子用户

 public UserInfo createProfileForUser(String name, int flags, @UserIdInt int userHandle) {

//创建指定user的子用户,且子用户的应用均可正常使用

        return createProfileForUser(name, flags, userHandle, null);

    }

 

//4.创建子用户,且子用户部分应用不可使用

 public UserInfo createProfileForUser(String name, int flags, @UserIdInt int userHandle,

            String[] disallowedPackages) {

        try {

    //创建指定user的子用户,且子用户的部分应用禁止使用

            return mService.createProfileForUser(name, flags, userHandle, disallowedPackages);

        } catch (RemoteException re) {

            throw re.rethrowFromSystemServer();

        }

    }

//5.在不允许创建子用户的情况下强行创建子用户,且子用户部分应用不可使用

    public UserInfo createProfileForUserEvenWhenDisallowed(String name, int flags,

            @UserIdInt int userHandle, String[] disallowedPackages) {

        try {

            return mService.createProfileForUserEvenWhenDisallowed(name, flags, userHandle,

                    disallowedPackages);

        } catch (RemoteException re) {

            throw re.rethrowFromSystemServer();

        }

    }

 

//6.创建严格受管控的子用户

public UserInfo createRestrictedProfile(String name) {

        try {

            UserHandle parentUserHandle = Process.myUserHandle();

            UserInfo user = mService.createRestrictedProfile(name,

                    parentUserHandle.getIdentifier());

            if (user != null) {

                AccountManager.get(mContext).addSharedAccountsFromParentUser(parentUserHandle,

                        UserHandle.of(user.id));

            }

            return user;

        } catch (RemoteException re) {

            throw re.rethrowFromSystemServer();

        }

    }

 

 

小结:UserManager给出了6种创建用户的方式,进一步分析则发现实质上一共调用了4种

UserManagerService的创建方式:

mService.createUser

mService.createProfileForUser

mService.createProfileForUserEvenWhenDisallowed

mService.createRestrictedProfile

 

实际上这4种方式在UserManagerService中最终都调用到最核心的方法createUserInternalUnchecked来完成用户创建。而他们的主要区别在于传入的Flag。

 

 

 

 

 

 

 

 

 

下面来跟踪这4种方式在UserManagerServices是如何一一走入createUserInternalUnchecked 

 

1.最常用的createUser。其特征为创建新用户时,不对新用户进行部分应用禁用,且不是创建子用户,且需要明确是否能够创建用户。

 

    public UserInfo createUser(String name, int flags) {

//普通模式入口,传入参数少。

        checkManageOrCreateUsersPermission(flags);

//不创建子用户,因此不传入主用户id,即USER_NULL

        return createUserInternal(name, flags, UserHandle.USER_NULL);

    }

 

    private UserInfo createUserInternal(String name, int flags, int parentId) {

//此方式表示创建的新用户,所有应用均可正常使用,于是第4个参数传入为null

        return createUserInternal(name, flags, parentId, null);

    }

 

    private UserInfo createUserInternal(String name, int flags, int parentId,

            String[] disallowedPackages) {

//这是比较完整的创建用户的参数,只是需要判断一下是否可以创建用户。

        String restriction = ((flags & UserInfo.FLAG_MANAGED_PROFILE) != 0)

                ? UserManager.DISALLOW_ADD_MANAGED_PROFILE

                : UserManager.DISALLOW_ADD_USER;

        if (hasUserRestriction(restriction, UserHandle.getCallingUserId())) {

//判断是否可以创建用户

            Log.w(LOG_TAG, "Cannot add user. " + restriction + " is enabled.");

            return null;

        }

//最终走到createUserInternalUnchecked 

        return createUserInternalUnchecked(name, flags, parentId, disallowedPackages);

    }

 

2.createProfileForUser和createUser基本一模一样,也是通过createUserInternal,传入参数中可以传入paretId和disallowedPackages。

 

    public UserInfo createProfileForUser(String name, int flags, int userId,

            String[] disallowedPackages) {

        checkManageOrCreateUsersPermission(flags);

//和createUser的区别就是增加主用户(paretId)和应用禁用(disallowedPackages)的参数入口

        return createUserInternal(name, flags, userId, disallowedPackages);

    }

 

private UserInfo createUserInternal(String name, int flags, int parentId,

            String[] disallowedPackages) {

//这是比较完整的创建用户的参数,只是需要判断一下是否可以创建用户。

        String restriction = ((flags & UserInfo.FLAG_MANAGED_PROFILE) != 0)

                ? UserManager.DISALLOW_ADD_MANAGED_PROFILE

                : UserManager.DISALLOW_ADD_USER;

        if (hasUserRestriction(restriction, UserHandle.getCallingUserId())) {

//判断是否可以创建用户

            Log.w(LOG_TAG, "Cannot add user. " + restriction + " is enabled.");

            return null;

        }

//最终走到createUserInternalUnchecked 

        return createUserInternalUnchecked(name, flags, parentId, disallowedPackages);

    }

 

 

3.createProfileForUserEvenWhenDisallowed 也是创建子用户,不经过createUserInternal来确认是否可以创建用户,而是直接进入createUserInternalUnchecked 

 

  public UserInfo createProfileForUserEvenWhenDisallowed(String name, int flags, int userId,String[] disallowedPackages) {

        checkManageOrCreateUsersPermission(flags);

//最终走到createUserInternalUnchecked 

        return createUserInternalUnchecked(name, flags, userId, disallowedPackages);

    }

 

 

 

4.createRestrictedProfile一个快捷入口,本质是调用createProfileForUser,自然最终走入createUserInternalUnchecked ,主要是锁定了flag

 

public UserInfo createRestrictedProfile(String name, int parentUserId) {

        checkManageOrCreateUsersPermission("setupRestrictedProfile");

        final UserInfo user = createProfileForUser(

                name, UserInfo.FLAG_RESTRICTED, parentUserId, null);

        if (user == null) {

            return null;

        }

        long identity = Binder.clearCallingIdentity();

        try {

            setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user.id);

            android.provider.Settings.Secure.putIntForUser(mContext.getContentResolver(),

                    android.provider.Settings.Secure.LOCATION_MODE,

                    android.provider.Settings.Secure.LOCATION_MODE_OFF, user.id);

            setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, true, user.id);

        } finally {

            Binder.restoreCallingIdentity(identity);

        }

        return user;

    }

小结:在创建用户的流程中,最终统一走到了createUserInternalUnchecked 方法,这个方法需要传入用户名,用户特征,主用户编号,禁用应用4个参数。当主用户名为空则表示普通用户,主用户编号不为空则创建的用户为主用户编号的子用户。而从开发接口来看,必须是设定子用户的路线才能设定禁用应用。

 

private UserInfo createUserInternalUnchecked(String name, int flags, int parentId,

            String[] disallowedPackages)

 

 

总结,今天对创建用户的接口进行了与对外接口有关部分的梳理。从app可以调用的UserManager对应的6个接口,到UserManagerService实际开放的4个接口,最终统一到了createUserInternalUnchecked 这一个创建用户的方法。

 

下一章将详细讲解createUserInternalUnchecked 的具体实现。

你可能感兴趣的:(源码剖析)