Android 多用户源码分析

从开发的角度进行考虑:
1、用户的增加,删除,查询,切换功能
2、各用户切换之后,文件系统的变化。

我们在学习源码的过程中,不要一开始就开始一头扎入源码中,试着将源码切块,然后各小块中Google 工程师都会给我们提供一些test模块,这儿其实是我们学习源码的一个很好的突破点。

这是我根据 test 文件写出的用户操作的 util。

package com.example.shoppingchen.qianmingtest;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.test.AndroidTestCase;
import android.app.ActivityManagerNative;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
import android.os.SystemProperties;
/**
 * Created by ShoppingChen on 2018/5/23.
 */

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.test.AndroidTestCase;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

import static junit.framework.Assert.assertTrue;

/**
 * Created by ShoppingChen on 2018/5/23.
 */

/**
 * 该工具类需要实现功能为:
 * 1、实现用户的创建
 * 2、实现用户的删除
 * 3、实现用户的修改
 * 4、实现用户的查询
 * 5、实现用户的相关文件夹的获取
 * 5、实现用户之间的切换
 */

public class UserUtils {
    //private static final String TAG = UserUtils.class.getSimpleName();
    private static final String TAG = "UserTestCXP";
    private Context mContext;
    private UserManager mUserManager;
    Object mUserLock = new Object();

    UserUtils(Context context){
        this.mContext = context;
        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
    }

    /**
     * 创建新的用户
     * @param userName 用户名
     * @param userType 用户类型
     * @return
     * @throws Exception
     */
    public UserInfo addUser(String userName,int userType) throws Exception{
        if(userType == -1){
            userType = UserInfo.FLAG_ADMIN;
        }
        UserInfo user = mUserManager.createUser(userName, userType);
        return user;
    }

    /**
     * 根据用户id移除用户
     * @param userId
     * @return
     * @throws Exception
     */
    public void removeUser(final int userId) throws Exception{
        new Thread(new Runnable() {
            @Override
            public void run() {
                removeMyUser(userId);
            }
        }).start();
    }

    /**
     * 通过id获取对应用户对象
     * @param userId
     * @return
     */
    public UserInfo getUserById(int userId){
        return mUserManager.getUserInfo(userId);
    }

    /**
     * 获取所有用户信息
     * @return
     */
    public String getAllUsers(){
        StringBuffer buffer = new StringBuffer();
        List<UserInfo> users = mUserManager.getUsers();
        for(UserInfo user : users){
            Log.d(TAG,user.toString());
            buffer.append(user.toString());
        }
        return  buffer.toString();
    }

    /**
     * 获取用户数量
     * @return
     */
    public int getUserCount(){
        return mUserManager.getUsers().size();
    }

    /**
     * 通过id移除用户
     * @param userId
     */
    private void removeMyUser(int userId) {
        synchronized (mUserLock) {
            mUserManager.removeUser(userId);
            while (mUserManager.getUserInfo(userId) != null) {
                try {
                    mUserLock.wait(1000);
                } catch (InterruptedException ie) {
                }
            }
        }
    }

    /**
     * 移除所有用户
     */
    public void removeExistingUsers() {
        List<UserInfo> list = mUserManager.getUsers();
        for (UserInfo user : list) {
            if (user.id != UserHandle.USER_OWNER) {
                removeMyUser(user.id);
            }
        }
    }

    /**
     * 切换用户
     * @param userId
     */
    public void switchUserNow(int userId) {
        try {
            ActivityManagerNative.getDefault().switchUser(userId);
        } catch (RemoteException re) {
            // Nothing to do
        }
    }

    /**
     * 根据文件路径拷贝文件(供测试使用)
     * @param src 源文件
     * @param destPath 目标文件路径
     * @return boolean 成功true、失败false
     */
    public boolean copyFile(File src, String destPath , String FileName) {

        boolean result = false;
        if ((src == null) || (destPath== null)) {
            return result;
        }
        File dest= new File(destPath + FileName);
        if (dest!= null && dest.exists()) {
            dest.delete(); // delete file
        }
        try {
            dest.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }

        FileChannel srcChannel = null;
        FileChannel dstChannel = null;

        try {
            srcChannel = new FileInputStream(src).getChannel();
            dstChannel = new FileOutputStream(dest).getChannel();
            srcChannel.transferTo(0, srcChannel.size(), dstChannel);
            result = true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return result;
        } catch (IOException e) {
            e.printStackTrace();
            return result;
        }
        try {
            srcChannel.close();
            dstChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
}

我们用过android 多用户功能的人都知道,各个用户之间是相互独立的,都无法查看其他人的用户目录,这在android系统中是怎么实现的呢?

这里写图片描述

所有用户的实际目录都是挂载在mnt/shell/emulated/对应用户id
我们所看到的 sdcard/下边的文件都是一个 mnt/shell 下对应用户的一个映射。

那这样的话,我们是不是可以去修改其它用户的信息了呢?
其实是不行的,因为用户权限的原因,只有root用户才能访问 mnt/shell 下边的文件,这就意味着,我们只有将我们的设备root才行。

猜你喜欢

转载自blog.csdn.net/chenxiaoping1993/article/details/80654051
今日推荐