我們可以感遭到,在Android 4.2中的1個比較顯著的改變就是加入了多用戶的支持。因多用戶手機專利早已被Symbian雇員注冊,故 android官方的多用戶切換目前僅支持平板裝備。
系統判斷當前裝備是不是支持多用戶模式的根據是配置文件config.xml中的config_multiuserMaximumUsers配置項。 其取值為整型,決定著當前裝備支持的最大用戶上限。默許值為1,即不支持多用戶。如需啟用多用戶,則設置此值 為大于1的值。在Nexus 7中,此值為8。
具體代碼的判斷位置在UserManager.java:
對用戶的操作目前未對普通利用開放,其相干API都有hide注解,并需要system權限。另外,用戶的添加和移除還 要需android.Manifest.permission.MANAGE_USERS權限。
用戶添加是通過調用UserManager的public UserInfo createUser(String name, int flags)方法進行的。其具體實現在UserManagerService的同名方法中。
在調用時,系統進行以下操作:
用戶創建后,會首先在/data/system/users/userlist.xml文件中保存新增加用戶的id,創建/data/system/users/ 用戶id 目錄,并將用戶信息保存至其下的用戶id.xml 文件中。其內容包括1些基本的用戶信息。
用戶切換是通過調用ActivityManager的public boolean switchUser(int userId)方法進行。1般通過 ActivityManagerNative.getDefault().switchUser(int userId)進行調用。
在調用時,系統進行以下操作
用戶移除是通過調用UserManager的 public boolean removeUser(int userHandle) 方法進行的。其具體實現一樣 是在UserManagerService的同名方法中。
在調用時,系統進行以下操作:
另外UserManager還提供了 public void wipeUser(int userHandle) 方法,用于刪除單個用戶的所有數據,但保存 用戶賬號。 此方法目前對應的底層實現還沒有完成。
與其它系統服務的實現類似,用戶管理也采取了經過Binder調用的遠程服務機制。UserManager為暴露給用戶的接 口,UserManagerService為接口的底層實現。其類圖以下所示:
UserManager是暴露出來的利用程序接口。對普通利用程序,提供用戶數查詢,用戶狀態判斷和用戶序列號查詢 等基本功能。 普通利用沒有用戶操作權限。
對系統利用,UserManager提供了創建/刪除/擦除用戶、用戶信息獲得、用戶句柄獲得等用戶操作的接口。均由遠 程調用UserManagerService服務的對應方法實現。
UserManager中提供了1個名為isUserAGoat()的方法。源碼中此方法直接返回了false。此方法的加入純潔是為了給 枯燥的編程生活帶來1絲樂趣,以便寫出:
這樣的語句。
與其它大部份Service1樣,UserManagerService的實現采取了 單例模式。在服務中,由組成為UserInfo類的散列 表mUsers保護所有的用戶狀態。
mUsers在系統啟動時由/data/system/users/userlist.xml讀取生成,并在運行期間動態改變。所有用戶的添加、刪 除操作,都終究序列化回此文件中。
ActivityManagerService目前加入了多用戶支持。負責保護裝備中存在的所有用戶狀態。服務以下述變量來記錄當 前處于“啟動”狀態的用戶。
用戶的啟動狀態對象為com.android.server.am.UserStartedState。其中指定的用戶狀態有4種:
完全的用戶生命周期為:
BOOTING->RUNNING->STOPPING->SHUTDOWN
用戶必須處于RUNNING狀態時,才能作為切換的目標用戶。所以在用戶切換流程中,首先要判斷當前用戶的狀態, 并啟動STOPPING/SHUTDOWN狀態的用戶。
用戶最早體驗到多用戶的入口位置即為鎖屏界面。鎖屏界面中加入了用戶切換組件: KeyguardMultiUserSelectorView類。
該類在裝備允許多用戶存在的情況下,顯示當前所有用戶的列表。并在用戶進行選擇后,調用 ActivityManagerNative.getDefault().switchUser(int userId)方法進行用戶切換。
對每一個用戶,Android都為其分配了單獨的存儲空間。標準的支持多用戶的外部存儲空間是由init.rc定義的環境 變量所指定:
在Dalvik虛擬機初始化的進程中,會以dalvik_system_Zygote.cpp中的mountEmulatedStorage函數,使用帶有 MS_BIND參數的mount命令, 將用戶對應的外部存儲卡目錄mount到上述定義的TARGET目錄下。其判斷利用userid的 方式為: 以當前利用的uid/100000,取得對應的userid,這段邏輯位于system/core/libcutils/multiuser.c中。
而Environment類中相應的獲得外部存儲目錄的方法,也是由上述環境變量所取得。對每一個用戶,其標準外部存 儲路徑為:
EMULATED_STORAGE_TARGET/userid/
比如:
/storage/emulated/0 為主用戶的外部存儲路徑。
在多用戶環境下,所有用戶安裝的利用依然同之前1樣,放置于/data/app目錄下。但本來/data/data的數據存儲位 置目前僅對主用戶有效,其余用戶的數據存儲目錄則位于/data/user/用戶id/目錄下。 此目錄的創建是在創建用戶 時由前述的MountService完成的。
對每一個用戶,系統都會以PackageuserState類來保護其安裝的軟件狀態。此列表以散列表的情勢存在,由 PackageSettingBase類保護。所有的包――用戶關系和狀態終究依然序列化至/data/system/package.xml中,并保存 /data/system/package-backup.xml作為備份。
目前代碼中已存在諸如 isGuestEnabled() 之類的方法。但沒有對開發公然,可以預計今后會加入Guest用戶, 實現“隨手玩玩”模式