国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android--多用戶模式

2019-11-08 00:21:09
字體:
來源:轉載
供稿:網友

Android中的多用戶與Windows的多用戶類似,可以支持多個用戶使用系統。通常,第一個在系統中注冊的用戶將默認成為系統管理員。

不同用戶的設置各不相同,并且不同用戶安裝的應用及應用數據也不相同。但是系統中和硬件相關的設置則是共用的,例如網絡設置等。

Android與Windows不同,用戶切換后前面用戶運行的后臺進程還可以繼續運行。這樣,進行用戶切換時無須中斷一些后臺進行的耗時操作(如下載)。

一、管理用戶的系統服務--UserManagerService

UserManagerService的主要功能是創建和刪除用戶,以及查詢用戶信息。

1、初始化

UserManagerService是在PackageManagerService的構造方法中創建的,如下:

[java] view plain copy sUserManager = new UserManagerService(context, this, mInstallLock, mPackages);  UserManagerService的構造方法,如下:[java] view plain copy UserManagerService(Context context, PackageManagerService pm,          Object installLock, Object packagesLock) {      this(context, pm, installLock, packagesLock,              Environment.getDataDirectory(),              new File(Environment.getDataDirectory(), "user"));  }  調用另一個構造方法,并多傳遞了兩個參數:/data目錄和/data/user文件。如下:[java] view plain copy PRivate UserManagerService(Context context, PackageManagerService pm,          Object installLock, Object packagesLock,          File dataDir, File baseUserPath) {      mContext = context;      mPm = pm;      mInstallLock = installLock;      mPackagesLock = packagesLock;      mHandler = new Handler();      synchronized (mInstallLock) {          synchronized (mPackagesLock) {              mUsersDir = new File(dataDir, USER_INFO_DIR);// /data/system/users              mUsersDir.mkdirs();              // Make zeroth user directory, for services to migrate their files to that location              File userZeroDir = new File(mUsersDir, "0");//第一個用戶的目錄/data/system/users/0              userZeroDir.mkdirs();              mBaseUserPath = baseUserPath;// /data/user              FileUtils.setPermissions(mUsersDir.toString(),                      FileUtils.S_IRWXU|FileUtils.S_IRWXG                      |FileUtils.S_IROTH|FileUtils.S_IXOTH,                      -1, -1);              mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);// /data/system/users/userlist.xml              initDefaultGuestRestrictions();              readUserListLocked();//分析用戶的信息文件              // Prune out any partially created/partially removed users.              ArrayList<UserInfo> partials = new ArrayList<UserInfo>();              for (int i = 0; i < mUsers.size(); i++) {                  UserInfo ui = mUsers.valueAt(i);                  if ((ui.partial || ui.guestToRemove) && i != 0) {                      partials.add(ui);//尋找userlist.xml文件中屬性partial為true的用戶                  }              }              for (int i = 0; i < partials.size(); i++) {                  UserInfo ui = partials.get(i);                  Slog.w(LOG_TAG, "Removing partially created user #" + i                          + " (name=" + ui.name + ")");                  removeUserStateLocked(ui.id);//屬性為partial表示創建沒完成的用戶,從系統中移除              }              sInstance = this;          }      }  }  在構造方法中創建了幾個目錄:/data/system/users、data/system/users/0、/data/system/users/userlist.xml等。之后設置基本的限制條件,如下:[java] view plain copy private void initDefaultGuestRestrictions() {      if (mGuestRestrictions.isEmpty()) {          mGuestRestrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, true);//"no_outgoing_calls"          mGuestRestrictions.putBoolean(UserManager.DISALLOW_SMS, true);//"no_sms"      }  }  然后調用readUserListLocked()方法解析/data/system/users/userlist.xml文件,這個文件保存了系統中所有用戶的id信息。文件內容如下:[java] view plain copy <?xml version='1.0' encoding='utf-8' standalone='yes' ?>  <users nextSerialNumber="11" version="5">      <guestRestrictions>          <restrictions no_outgoing_calls="true" no_sms="true" />      </guestRestrictions>      <user id="0" />      <user id="10" />  </users>  得到id信息后還有讀取保存了用戶注冊信息的xml文件,以用戶id的數字表示,如0.xml。內容如下:[java] view plain copy <?xml version='1.0' encoding='utf-8' standalone='yes' ?>  <user id="0" serialNumber="0" flags="19" created="0" lastLoggedIn="1436392413074">      <name>Owner</name>      <restrictions />  </user>  讀取用戶的xml文件內容后,將根據文件內容來創建和初始化一個UserInfo對象來保存信息,并把該對象加入到mUsers列表中。如果xml文件中某個用戶的屬性中有partial="true',則表示這個用戶沒有完全創建成功,需要從系統中移除掉。

這樣UserManagerService的初始化工作就完成了,主要的工作是分析userlist.xml文件,并創建了mUsers列表中的UserInfo對象。

2、UserInfo的定義

在UserManagerService中,UserInfo對象代表用戶,定義如下:[java] view plain copy public class UserInfo implements Parcelable {        /** 8 bits for user type 用戶類型 */      public static final int FLAG_MASK_USER_TYPE = 0x000000FF;        /**      * Primary user. Only one user can have this flag set. Meaning of this      * flag TBD.主用戶的標志,通常是第一個Id為0的用戶      */      public static final int FLAG_PRIMARY = 0x00000001;        /**      * User with administrative privileges. Such a user can create and      * delete users.admin用戶標志,有此標志才能創建和刪除用戶      */      public static final int FLAG_ADMIN   = 0x00000002;        /**      * Indicates a guest user that may be transient.guest用戶標志      */      public static final int FLAG_GUEST   = 0x00000004;        /**      * Indicates the user has restrictions in privileges, 標識權限受限的用戶,具體受限功能未定。      * Exact meaning TBD. For instance, maybe they can't install apps or administer WiFi access pts.      */      public static final int FLAG_RESTRICTED = 0x00000008;        /**      * Indicates that this user has gone through its first-time initialization.標識該用戶是否已經初始化      */      public static final int FLAG_INITIALIZED = 0x00000010;        /**      * Indicates that this user is a profile of another user, for example holding a users      * corporate data.標識該UserInfo是用戶的信息,還是一份profile      */      public static final int FLAG_MANAGED_PROFILE = 0x00000020;        /**      * Indicates that this user is disabled.標識該用戶是否已經被“禁止”      */      public static final int FLAG_DISABLED = 0x00000040;        public static final int NO_PROFILE_GROUP_ID = -1;//profile group id 的無效值定義        public int id;//用戶id      public int serialNumber;//用戶的序列號,不會重復      public String name;//用戶的名稱      public String iconPath;//用戶的頭像路徑      public int flags;//用戶的標志      public long creationTime;//創建用戶的時間      public long lastLoggedInTime;//上次登錄的時間      public int profileGroupId;//用戶的profile group id        /** User is only partially created. */      public boolean partial;//此標志為true,表示用戶沒有創建完成      public boolean guestToRemove;  注意:用戶id用來標識用戶,用戶刪除后它的id會分配給下一個新建的用戶,保持id號的連續;而serialNumber則是一個在設備中不會重復的數字,用來唯一標識一個用戶,如果應用中希望記錄和某個用戶相關的信息,最好使用serialNumber來表示用戶,而不是用戶id。

3、用戶限制(Restriction)

Android5.1的UserManager中定義了很多和用戶相關的限制,這樣管理員在創建用戶時就能通過這些限制來給予不同用戶不同的權限,介紹如下:[java] view plain copy public static final String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";//限制修改用戶賬號  public static final String DISALLOW_CONFIG_WIFI = "no_config_wifi";//限制配置WiFi  public static final String DISALLOW_INSTALL_APPS = "no_install_apps";//限制安裝app  public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";//限制卸載app  public static final String DISALLOW_SHARE_LOCATION = "no_share_location";//限制共享地理位置  public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";//限制安裝本地應用  public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";//限制配置藍牙  public static final String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";//限制通過usb傳輸文件  public static final String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";//限制配置設備的安全設置  public static final String DISALLOW_REMOVE_USER = "no_remove_user";//限制刪除用戶  public static final String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";//限制使用調試功能  public static final String DISALLOW_CONFIG_VPN = "no_config_vpn";//限制配置VPN  public static final String DISALLOW_CONFIG_TETHERING = "no_config_tethering";//限制配置Tether  public static final String DISALLOW_FACTORY_RESET = "no_factory_reset";//限制進行出廠設置  public static final String DISALLOW_ADD_USER = "no_add_user";//限制創建用戶  public static final String ENSURE_VERIFY_APPS = "ensure_verify_apps";//對該用戶安裝的app要進行校驗  public static final String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";//限制用戶配置小區廣播  public static final String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";//限制配置移動網絡  public static final String DISALLOW_APPS_CONTROL = "no_control_apps";//限制進行清除應用數據和緩存的操作  public static final String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";//限制掛載  public static final String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";//限制對microphone進行靜音  public static final String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";//限制調節音量  public static final String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls";//限制撥打電話  public static final String DISALLOW_SMS = "no_sms";//限制發送短信  public static final String DISALLOW_CREATE_WINDOWS = "no_create_windows";//限制用戶的應用進行彈窗功能  public static final String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste";//限制對profile進行復制、粘貼  public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";//限制  

4、添加用戶

UserManagerService服務中添加用戶的接口是createUser(),如下:

[java] view plain copy public UserInfo createUser(String name, int flags) {      checkManageUsersPermission("Only the system can create users");        return createUserInternal(name, flags, UserHandle.USER_NULL);  }  createUser()方法首先檢查調用者的權限,只有system身份的進程才能調用這個方法。然后調用createUserInternal()方法繼續執行,如下:[java] view plain copy     private UserInfo createUserInternal(String name, int flags, int parentId) {          if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(                  UserManager.DISALLOW_ADD_USER, false)) {//獲取是否有添加用戶的權限              Log.w(LOG_TAG, "Cannot add user. DISALLOW_ADD_USER is enabled.");              return null;          }          final boolean isGuest = (flags & UserInfo.FLAG_GUEST) != 0;          final long ident = Binder.clearCallingIdentity();          UserInfo userInfo = null;          try {              synchronized (mInstallLock) {                  synchronized (mPackagesLock) {                      UserInfo parent = null;                      if (parentId != UserHandle.USER_NULL) {                          parent = getUserInfoLocked(parentId);                          if (parent == null) return null;                      }                      // 如果添加的不是Guest用戶,而且達到上限數,返回                      if (!isGuest && isUserLimitReachedLocked()) {                          return null;                      }                      // 如果添加的是Guest用戶,但是已經有Guest用戶存在,返回                      if (isGuest && findCurrentGuestUserLocked() != null) {                          return null;                      }                      //                      if ((flags & UserInfo.FLAG_MANAGED_PROFILE) != 0                              && numberOfUsersOfTypeLocked(UserInfo.FLAG_MANAGED_PROFILE, true)                                  >= MAX_MANAGED_PROFILES) {//目前MAX_MANAGED_PROFILES最大是1                          return null;//如果創建的是一個用戶的profile,檢查該用戶是否已經有profile                      }                      int userId = getNextAvailableIdLocked();//得到新用戶ID                      userInfo = new UserInfo(userId, name, null, flags);                      File userPath = new File(mBaseUserPath, Integer.toString(userId));                      userInfo.serialNumber = mNextSerialNumber++;                      long now = System.currentTimeMillis();                      userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;                      userInfo.partial = true;//將partial屬性設為true                      Environment.getUserSystemDirectory(userInfo.id).mkdirs();                      mUsers.put(userId, userInfo);//把新用戶信息添加到mUsers                      writeUserListLocked();//把用戶信息寫到文件userlist.xml中                      if (parent != null) {                          if (parent.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {                              parent.profileGroupId = parent.id;                              writeUserLocked(parent);                          }                          userInfo.profileGroupId = parent.profileGroupId;                      }                      writeUserLocked(userInfo);//創建用戶的信息文件10.xml                      mPm.createNewUserLILPw(userId, userPath);                      userInfo.partial = false;//創建成功,將partial設為false                      writeUserLocked(userInfo);//更新用戶的信息文件                      updateUserIdsLocked();                      Bundle restrictions = new Bundle();                      mUserRestrictions.append(userId, restrictions);                  }              }              if (userInfo != null) {//廣播用戶創建成功的消息                  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;        (1)檢查調用進程所屬用戶是否被限制添加用戶。

(2)調用isUserLimitReachedLocked()方法來確定是否還能創建更多的用戶。isUserLimitReachedLocked()方法將調用getMaxSupportedUsers()方法得到系統允許的最大用戶數和當前用戶數進行比較。

(3)調用getNextAvailableIdLocked()方法得到新的用戶id。getNextAvailableIdLocked()方法會從10開始查找,如果某個用戶Id還沒有使用,則將它返回。

(4)根據用戶id創建用戶的數據目錄。同時為用戶創建UserInfo對象,并加入到mUsers列表中。

(5)向userlist.xml文件中加入用戶的id信息。在/data/system/users/目錄下創建以用戶id數字表示的xml文件,保存UserInfo中的用戶信息,文件中partial屬性會被設為true。

(6)調用PackageManagerService的createNewuserLILPw()方法,在新建用戶的目錄下為所有應用創建數據目錄。

(7)更新用戶的信息文件,將xml文件中的partial屬性移除,這樣新用戶就創建完成了。使用partial屬性的目的是為了防止調用createNewUserLILPw()方法出錯,不能成功創建用戶。利用這個標志,系統重啟時可以清除掉創建失敗的用戶。

(8)廣播加入新用戶的消息Intent.ACTION_USER_ADDED。

5、Guest用戶

在Android5.0中,創建Guest用戶需要通過UserManager的createGuest()方法來完成。如下:[java] view plain copy public UserInfo createGuest(Context context, String name) {      UserInfo guest = createUser(name, UserInfo.FLAG_GUEST);//創建Guest用戶      if (guest != null) {          Settings.Secure.putStringForUser(context.getContentResolver(),                  Settings.Secure.SKip_FIRST_USE_HINTS, "1", guest.id);          try {//對Guest用戶進行權限限制              Bundle guestRestrictions = mService.getDefaultGuestRestrictions();              guestRestrictions.putBoolean(DISALLOW_SMS, true);              guestRestrictions.putBoolean(DISALLOW_INSTALL_UNKNOWN_SOURCES, true);              mService.setUserRestrictions(guestRestrictions, guest.id);          } catch (RemoteException re) {              Log.w(TAG, "Could not update guest restrictions");          }      }      return guest;  }  createGuest()先調用createUser()方法創建一個Guest用戶,然后再調用setUserRestrictions()方法進一步對Guest用戶進行限制。因此,Guest用戶和普通用戶的區別就在于權限不同。

6、刪除用戶

UserManagerService服務中刪除用戶的接口是removeUser()方法,如下:

[java] view plain copy public boolean removeUser(int userHandle) {      checkManageUsersPermission("Only the system can remove users");      if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(              UserManager.DISALLOW_REMOVE_USER, false)) {          Log.w(LOG_TAG, "Cannot remove user. DISALLOW_REMOVE_USER is enabled.");          return false;      }//檢查調用進程的權限以及進程所屬的用戶是否被“限制”        long ident = Binder.clearCallingIdentity();      try {          final UserInfo user;          synchronized (mPackagesLock) {              user = mUsers.get(userHandle);              if (userHandle == 0 || user == null || mRemovingUserIds.get(userHandle)) {                  return false;              }                // 將userHandle放入mRemovingUserIds列表,防止重復刪除一個用戶              mRemovingUserIds.put(userHandle, true);                try {                  mAppOpsService.removeUser(userHandle);              } catch (RemoteException e) {                  Log.w(LOG_TAG, "Unable to notify AppOpsService of removing user", e);              }              // Set this to a partially created user, so that the user will be purged              // on next startup, in case the runtime stops now before stopping and              // removing the user completely.              user.partial = true;              // Mark it as disabled, so that it isn't returned any more when              // profiles are queried.              user.flags |= UserInfo.FLAG_DISABLED;              writeUserLocked(user);//更新用戶信息文件          }            if (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID                  && user.isManagedProfile()) {              // Send broadcast to notify system that the user removed was a              // managed user.              sendProfileRemovedBroadcast(user.profileGroupId, user.id);          }            if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle);          int res;          try {//停止正在運行的用戶              res = ActivityManagerNative.getDefault().stopUser(userHandle,                      new IStopUserCallback.Stub() {//回調函數                          @Override                          public void userStopped(int userId) {                              finishRemoveUser(userId);                          }                          @Override                          public void userStopAborted(int userId) {                          }                      });          } catch (RemoteException e) {              return false;          }          return res == ActivityManager.USER_OP_SUCCESS;      } finally {          Binder.restoreCallingIdentity(ident);      }  }  removeUser()方法并沒有立即刪除用戶相關的文件,而是首先將用戶信息中的partial屬性改為true。這樣的好處是,如果后面的過程被意外終止了,系統重啟后還是會刪除該用戶所有目錄和文件。

考慮到被刪除的用戶可能正在運行,因此,removeUser()方法要調用ActivityManagerService的stopUser()方法來改變該用戶的運行狀態,結束后,AMS將調用函數參數中的回調方法,最終調用到finishRemoveUser()方法。如下:

[java] view plain copy void finishRemoveUser(final int userHandle) {      if (DBG) Slog.i(LOG_TAG, "finishRemoveUser " + userHandle);      // Let other services shutdown any activity and clean up their state before completely      // wiping the user's system directory and removing from the user list      long ident = Binder.clearCallingIdentity();      try {          Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);          addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);          mContext.sendOrderedBroadcastAsUser(addedIntent, UserHandle.ALL,                  android.Manifest.permission.MANAGE_USERS,                    new BroadcastReceiver() {                      @Override                      public void onReceive(Context context, Intent intent) {                          if (DBG) {                              Slog.i(LOG_TAG,                                      "USER_REMOVED broadcast sent, cleaning up user data "                                      + userHandle);                          }                          new Thread() {                              public void run() {                                  synchronized (mInstallLock) {                                      synchronized (mPackagesLock) {                                          removeUserStateLocked(userHandle);                                      }                                  }                              }                          }.start();                      }                  },                    null, Activity.RESULT_OK, null, null);      } finally {          Binder.restoreCallingIdentity(ident);      }  }  在finishRemoveUser()方法中發出了廣播Intent.ACTION_USER_REMOVED,同時也創建了一個BroadcastReceiver對象來接收這個廣播。注意,這時創建的廣播接收器將最后才能收到廣播通知。這是為了讓系統中其他關心這條廣播的地方先處理,最后才回到這里繼續完成刪除用戶的工作。收到廣播后,考慮到后面的工作還很耗時,因此,在onReceiver()方法中啟動了一個線程來運行removeUserStateLocked()方法。代碼如下:[java] view plain copy private void removeUserStateLocked(final int userHandle) {      // Cleanup package manager settings調用PackageManagerService的cleanUpUserLILPw方法刪除所有用戶目錄下app的數據      mPm.cleanUpUserLILPw(this, userHandle);        // Remove this user from the list在mUsers列表中刪除用戶的UserInfo對象      mUsers.remove(userHandle);        mRestrictionsPinStates.remove(userHandle);//從mRestrictionsPinStates列表中移除用戶      // Remove user file刪除用戶的信息文件      AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX));      userFile.delete();      // Update the user list      writeUserListLocked();//更新文件userlists.xml,移除用戶信息      updateUserIdsLocked();      removeDirectoryRecursive(Environment.getUserSystemDirectory(userHandle));//刪除用戶目錄下的所有文件  }  removeUserStateLocked()方法將刪除所有用戶相關的文件。首先是app的數據文件,然后是用戶信息文件和userlist.xml中的用戶Id信息,最后將用戶目錄下的所有文件都刪除。

二、PackageManagerService和多用戶

在多用戶的環境中,所有用戶安裝的應用還是位于/data/app目錄,但是這些應用的數據在每個用戶的目錄/data/user/<用戶id>/下都有單獨的一份。目錄/data/data也還保存應用的數據,但這些數據只對id為0的用戶有效。

1、創建用戶的應用數據

上面講到創建用戶時會調用PackageManagerService的createNewUserLILPw()方法,如下:

[java] view plain copy /** Called by UserManagerService */  void createNewUserLILPw(int userHandle, File path) {      if (mInstaller != null) {          mInstaller.createUserConfig(userHandle);          mSettings.createNewUserLILPw(this, mInstaller, userHandle, path);      }  }  createNewUserLILPw()方法只是調用了mInstaller的createUserConfig()和mSettings的createNewUserLILPw()方法。

我們先看下mInstaller的createUserConfig()方法是如何處理的,如下:

[java] view plain copy public int createUserConfig(int userId) {      StringBuilder builder = new StringBuilder("mkuserconfig");      builder.append(' ');      builder.append(userId);      return mInstaller.execute(builder.toString());  }  mInstaller是InstallerConnection的對象,這里調用InstallConnection對象的execute()方法,如下:[java] view plain copy public int execute(String cmd) {      String res = transact(cmd);      try {          return Integer.parseInt(res);      } catch (NumberFormatException ex) {          return -1;      }  }  這里實現了與installd服務通信的過程,具體操作是由installd服務完成的。再看下mSettings的createNewUserLILPw()方法,我們知道mSettings中保存的是從文件中讀取的所有應用的信息。如下:[java] view plain copy void createNewUserLILPw(PackageManagerService service, Installer installer,          int userHandle, File path) {      path.mkdir();//創建用戶保存應用數據的目錄/data/user      FileUtils.setPermissions(path.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG              | FileUtils.S_IXOTH, -1, -1);      for (PackageSetting ps : mPackages.values()) {          if (ps.pkg == null || ps.pkg.applicationInfo == null) {              continue;          }//對每一個應用在用戶的目錄下創建數據目錄          // Only system apps are initially installed.          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,                  ps.pkg.applicationInfo.seinfo);      }      readDefaultPreferredAppsLPw(service, userHandle);      writePackageRestrictionsLPr(userHandle);  }  createNewUserLILPw()方法會遍歷mPackages列表,這個列表保存的是系統中所有已安裝的應用信息,然后針對每一個應用調用installer的createUserData()方法,調用Installer的方法最終會調用installd守護進程的命令,這里最終調用installd的“mkuserdata”命令來執行應用數據目錄的創建工作。[java] view plain copy public int createUserData(String name, int uid, int userId, String seinfo) {      StringBuilder builder = new StringBuilder("mkuserdata");      builder.append(' ');      builder.append(name);      builder.append(' ');      builder.append(uid);      builder.append(' ');      builder.append(userId);      builder.append(' ');      builder.append(seinfo != null ? seinfo : "!");           return mInstaller.execute(builder.toString());  }  同時每個應用的設置對象PackageSetting中都有一個數組userState,表示應用已經被安裝到哪些用戶中,這里調用ps的setInstalled方法就是向數組userState中插入用戶的信息。

調用readDefaultPreferredAppsLPw()方法是為了分析目錄/etc/preferred-apps所有的xml文件,這個目錄下的xml文件保存的是設備使用者指定的響應某個intent的最合適的組件。因為每個用戶都可以指定它喜歡的最合適的組件,所以每個用戶都需要在mPreferredActivities列表中加入它自己的PreferredIntentResolver對象,這個對象中保存的就是intent和組件的關聯數據。

2、刪除用戶的應用數據

PackageManagerService中刪除用戶的方法是cleanUpUserLILPw()方法,如下:

[java] view plain copy /** Called by UserManagerService */  void cleanUpUserLILPw(UserManagerService userManager, int userHandle) {      mDirtyUsers.remove(userHandle);      mSettings.removeUserLPw(userHandle);      mPendingBroadcasts.remove(userHandle);      if (mInstaller != null) {          // Technically, we shouldn't be doing this with the package lock          // held.  However, this is very rare, and there is already so much          // other disk I/O going on, that we'll let it slide for now.          mInstaller.removeUserDataDirs(userHandle);//刪除用戶目錄下所有應用的數據      }      mUserNeedsBadging.delete(userHandle);      removeUnusedPackagesLILPw(userManager, userHandle);  }  cleanUpUserLILPw方法主要的工作就是調用mInstaller的removeUserDataDirs()方法來刪除用戶目錄下所有應用的數據。同時調用mSettings的removeUserLPw()方法來刪除PackageManagerService中和用戶相關的數據,如下:[java] view plain copy void removeUserLPw(int userId) {      Set<Entry<String, PackageSetting>> entries = mPackages.entrySet();      for (Entry<String, PackageSetting> entry : entries) {          entry.getValue().removeUser(userId);      }<span style="font-family: Arial, Helvetica, sans-serif;">//刪除每個應用信息中該用戶的信息</span>      mPreferredActivities.remove(userId);//刪除mPreferredActivities列表中該用戶的數據      File file = getUserPackagesStateFile(userId);      file.delete();//刪除該用戶目錄下的package-restrictions.xml文件      file = getUserPackagesStateBackupFile(userId);      file.delete();      removeCrossProfileIntentFiltersLPw(userId);  }  

三、ActivityManagerService和多用戶

UserManagerService主要管理用戶的賬號信息,運行中的用戶管理由ActivityManagerService實行。

1、用戶的狀態

用戶有四種運行狀態,定義如下:

[java] view plain copy public final class UserStartedState {      // User is first coming up.      public final static int STATE_BOOTING = 0;//用戶正在啟動      // User is in the normal running state.      public final static int STATE_RUNNING = 1;//用戶正在運行      // User is in the initial process of being stopped.      public final static int STATE_STOPPING = 2;//用戶正在停止      // User is in the final phase of stopping, sending Intent.ACTION_SHUTDOWN.      public final static int STATE_SHUTDOWN = 3;//用戶已經關閉  在AMS中,變量mCurrentUserId記錄了當前的用戶Id,mStartedUsers列表則保存了正在運行的用戶,只有在mStartedUsers列表中的用戶才會有上面這4中狀態,不在列表中的是已經注冊了但是沒有運行的用戶。

2、切換當前用戶

ActivityManagerService中提供了切換當前用戶的接口switchUser(),如下:[java] view plain copy public boolean switchUser(final int userId) {      enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, userId);      String userName;      synchronized (this) {          UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);//獲取userId對應的UserInfo          if (userInfo == null) {              Slog.w(TAG, "No user info for user #" + userId);              return false;          }          if (userInfo.isManagedProfile()) {//如果這個UserInfo只是User的另一份profile,退出              Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");              return false;          }          userName = userInfo.name;          mTargetUserId = userId;      }      mHandler.removeMessages(START_USER_SWITCH_MSG);      mHandler.sendMessage(mHandler.obtainMessage(START_USER_SWITCH_MSG, userId, 0, userName));//發送切換用戶的消息      return true;  }  switchUser()先調用getUserInfo()方法得到userId對應的用戶信息,然后通過isManagedProfile()方法來判斷這份UserInfo是否只是一個profile(Android中允許一個用戶還擁有另一份profile)。如果確實是一個用戶,則發出消息START_USER_SWITCH_MSG。

對消息START_USER_SWITCH_MSG的處理是調用方法showUserSwitchDialog,這個方法將彈出一個對話框來確定是否要進行用戶切換,一旦用戶點擊確定按鈕后,調用startUserInForeground()方法

[java] view plain copy case START_USER_SWITCH_MSG: {      showUserSwitchDialog(msg.arg1, (String) msg.obj);      break;  }  [java] view plain copy private void showUserSwitchDialog(int userId, String userName) {      // The dialog will show and then initiate the user switch by calling startUserInForeground      Dialog d = new UserSwitchingDialog(this, mContext, userId, userName,              true /* above system */);      d.show();  }  

startUserInForeground()方法如下:

[java] view plain copy /**  * Start user, if its not already running, and bring it to foreground.  */  boolean startUserInForeground(final int userId, Dialog dlg) {      boolean result = startUser(userId, /* foreground */ true);      dlg.dismiss();      return result;  }  在startUserInForeground()方法中只是調用了startUser()方法,如下:[java] view plain copy private boolean startUser(final int userId, final boolean foreground) {      if (checkCallingPermission(INTERACT_ACROSS_USERS_FULL)              != PackageManager.PERMISSION_GRANTED) {          。。。。。。//檢查調用者權限      }      final long ident = Binder.clearCallingIdentity();      try {          synchronized (this) {              final int oldUserId = mCurrentUserId;              if (oldUserId == userId) {                  return true;//當前用戶已經是參數指定的用戶,退出              }                mStackSupervisor.setLockTaskModeLocked(null, false, "startUser");                final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);              。。。。。。//一些錯誤處理,返回false              if (foreground) {                  mWindowManager.startFreezingScreen(R.anim.screen_user_exit,                          R.anim.screen_user_enter);              }                boolean needStart = false;                // 如果用戶還沒有啟動,需要先啟動用戶,切換用戶狀態為正在啟動              if (mStartedUsers.get(userId) == null) {                  mStartedUsers.put(userId, new UserStartedState(new UserHandle(userId), false));                  updateStartedUserArrayLocked();                  needStart = true;              }                final Integer userIdInt = Integer.valueOf(userId);              mUserLru.remove(userIdInt);              mUserLru.add(userIdInt);//調整用戶在mUserLru列表中的位置,當前用戶位于最末的位置                if (foreground) {//前臺切換                  mCurrentUserId = userId;//切換當前用戶                  mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up                  updateCurrentProfileIdsLocked();                  mWindowManager.setCurrentUser(userId, mCurrentProfileIds);//在WMS這設置當前用戶                  mWindowManager.lockNow(null);//鎖上屏幕              } else {                  final Integer currentUserIdInt = Integer.valueOf(mCurrentUserId);                  updateCurrentProfileIdsLocked();                  mWindowManager.setCurrentProfileIds(mCurrentProfileIds);                  mUserLru.remove(currentUserIdInt);                  mUserLru.add(currentUserIdInt);              }                final UserStartedState uss = mStartedUsers.get(userId);                // Make sure user is in the started state.  If it is currently              // stopping, we need to knock that off.              if (uss.mState == UserStartedState.STATE_STOPPING) {                  // 如果用戶的狀態為正在停止,切換為正在運行                  uss.mState = UserStartedState.STATE_RUNNING;                  updateStartedUserArrayLocked();                  needStart = true;              } else if (uss.mState == UserStartedState.STATE_SHUTDOWN) {                  // 如果用戶的狀態為正在關閉,切換為正在啟動                  uss.mState = UserStartedState.STATE_BOOTING;                  updateStartedUserArrayLocked();                  needStart = true;              }                if (uss.mState == UserStartedState.STATE_BOOTING) {                  //如果用戶的狀態為正在啟動,發送消息SYSTEM_USER_START_MSG                  mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_START_MSG, userId, 0));              }                if (foreground) {                  mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_CURRENT_MSG, userId,                          oldUserId));                  mHandler.removeMessages(REPORT_USER_SWITCH_MSG);                  mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);                  mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,                          oldUserId, userId, uss));                  mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,                          oldUserId, userId, uss), USER_SWITCH_TIMEOUT);              }                if (needStart) {                  // 如果切換前用戶不在STATE_RUNNING狀態,向該用戶發送廣播ACTION_USER_STARTED                  Intent intent = new Intent(Intent.ACTION_USER_STARTED);                  intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY                          | Intent.FLAG_RECEIVER_FOREGROUND);                  intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);                  broadcastIntentLocked(null, null, intent,                          null, null, 0, null, null, null, AppOpsManager.OP_NONE,                          false, false, MY_PID, Process.SYSTEM_UID, userId);              }                if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {                  if (userId != UserHandle.USER_OWNER) {//如果用戶還沒初始化,向該用戶發送廣播ACTION_USER_INITIALIZE                      Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);                      intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);                      broadcastIntentLocked(null, null, intent, null,                              new IIntentReceiver.Stub() {                                  public void performReceive(Intent intent, int resultCode,                                          String data, Bundle extras, boolean ordered,                                          boolean sticky, int sendingUser) {                                      onUserInitialized(uss, foreground, oldUserId, userId);                                  }                              }, 0, null, null, null, AppOpsManager.OP_NONE,                              true, false, MY_PID, Process.SYSTEM_UID,                              userId);                      uss.initializing = true;                  } else {//否則直接調用UserManagerService的makeInitialized方法                      getUserManagerLocked().makeInitialized(userInfo.id);                  }              }                if (foreground) {                  if (!uss.initializing) {//如果用戶已經初始化了,將它設為前臺用戶                      moveUserToForeground(uss, oldUserId, userId);                  }              } else {//否則先將用戶加入到mStartingBackgroundUser中                  mStackSupervisor.startBackgroundUserLocked(userId, uss);              }                if (needStart) {//如果用戶不在STATE_RUNNING狀態,向所有用戶發送廣播ACTION_USER_STARTING                  Intent intent = new Intent(Intent.ACTION_USER_STARTING);                  intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);                  intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);                  broadcastIntentLocked(null, null, intent,                          null, new IIntentReceiver.Stub() {                              @Override                              public void performReceive(Intent intent, int resultCode, String data,                                      Bundle extras, boolean ordered, boolean sticky, int sendingUser)                                      throws RemoteException {                              }                          }, 0, null, null,                          INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE,                          true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);              }          }      } finally {          Binder.restoreCallingIdentity(ident);      }        return true;  }  startUser()方法代碼較長。方法中先確定用戶的狀態,如果用戶還沒有運行,那么mStartedUsers列表中將不會有用戶的信息,因此,需要先創建表示用戶狀態的對象UserStartedState,然后加入到mStartedUsers列表中。同時還要調整用戶在mUserLru列表中的位置到最后一項。系統中同時運行的用戶數量最多為3個(目前的定義),mUserLru列表就是記錄用戶的登錄順序,在需要時會停止多余的用戶運行。

對于已經在mStartedUsers列表中的用戶,首先判定它的狀態是否為STATE_RUNNING,如果不是,則需要完成狀態轉換,如果處于STATE_STOPPING狀態,直接轉換為STATE_RUNNING狀態,如果處于STATE_SHUTDOWN狀態,先轉換為STATE_BOOTING狀態。因此,switchUser()方法結束后用戶有可能處于STATE_BOOTING狀態,那么用戶什么時候會再切換到STATE_RUNNING狀態呢?稍候分析。

切換用戶的工作還包括設置記錄當前用戶id的變量mCurrentUserId,調用WMS的setCurrentUser()方法來改變當前用戶、鎖定當前的屏幕等。

除了這些工作,startUser()方法最重要的工作是廣播和用戶相關的Intent。因為用戶切換還牽扯到很多模塊,例如壁紙管理、輸入法、賬號管理模塊,他們都需要知道當前用戶已經發生了變化,然后做出相應的調整。這里要注意廣播的對象,有些是面向新用戶的,有些是面向舊用戶,有些面向所有用戶。

(1)如果切換前用戶不在STATE_RUNNING狀態,向該用戶發送廣播ACTION_USER_STARTED。

(2)id不為0的用戶如果還沒有初始化,向該用戶發送廣播ACTION_USER_INITIALIZE。

(3)調用sendUserSwitchBroadcastsLocked()方法向舊用戶發送廣播ACTION_USER_BACKGROUND,向新用戶發送廣播ACTION_USER_FOREGROUND,向所有用戶發送廣播ACTION_USER_SWUTCHED。

(4)如果切換前用戶不在STATE_RUNNING狀態,向所有用戶發送廣播ACTION_USER_STARTING。

此外,startUser()方法中還會發兩條消息:REPORT_USER_SWITCH_MSG和USER_SWITCH_TIMEOUT_MSG。其中REPORT_USER_SWITCH_MSG消息處理方法是dispatchUserSwitch,如下:

[java] view plain copy case REPORT_USER_SWITCH_MSG: {      dispatchUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);      break;  }  [java] view plain copy void dispatchUserSwitch(final UserStartedState uss, final int oldUserId,          final int newUserId) {      final int N = mUserSwitchObservers.beginBroadcast();      if (N > 0) {          final IRemoteCallback callback = new IRemoteCallback.Stub() {              int mCount = 0;              @Override              public void sendResult(Bundle data) throws RemoteException {                  synchronized (ActivityManagerService.this) {                      if (mCurUserSwitchCallback == this) {                          mCount++;//如果收到一條返回結果的調用,mCount++                          if (mCount == N) {//如果所有結果都返回了,發送繼續處理的消息                              sendContinueUserSwitchLocked(uss, oldUserId, newUserId);                          }                      }                  }              }          };          synchronized (this) {              uss.switching = true;              mCurUserSwitchCallback = callback;          }          for (int i=0; i<N; i++) {              try {//調用觀測對象的onUserSwitching方法                  mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(                          newUserId, callback);              } catch (RemoteException e) {              }          }      } else {//如果沒有觀測對象,直接調用sendContinueUserSwitchLocked          synchronized (this) {              sendContinueUserSwitchLocked(uss, oldUserId, newUserId);          }      }      mUserSwitchObservers.finishBroadcast();  }  dispatchUserSwitch()方法的主要作用是調用mUserSwitchObservers列表中IUserSwitchObserver對象的onUserSwitching()接口。如果系統中有模塊對用戶切換感興趣,可以調用AMS的registerUserSwitchObserver()接口來注冊一個觀測對象,這個對象將會保存到mUserSwitchObservers列表中。注冊觀測對象的模塊在它的回調接口onUserSwitching()的處理中需要在調用傳遞的參數對象callback的sendResult方法來通知AMS。我們看下上面代碼中的sendResult()方法,只有所有注冊者都調用了sendResult()方法,mCount最后才會等于N,這時才會調用sendContinueUserSwitchLocked方法來發送CONTINUE_USER_SWITCH_MSG消息來繼續切換用戶。

我們看下USER_SWITCH_TIMEOUT_MSG消息的處理,發送USER_SWITCH_TIMEOUT_MSG消息是為了防止對CONTINUE_USER_SWITCH_MSG消息的處理時間過長,畢竟只有所有注冊者處理完成才能繼續。Android5.1不同于以往版本,這里會繼續發送CONTINUE_USER_SWITCH_MSG消息,繼續進行用戶切換。如下:

[java] view plain copy case USER_SWITCH_TIMEOUT_MSG: {      timeoutUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);      break;  }  [java] view plain copy void timeoutUserSwitch(UserStartedState uss, int oldUserId, int newUserId) {      synchronized (this) {          Slog.w(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId);          sendContinueUserSwitchLocked(uss, oldUserId, newUserId);      }  }  [java] view plain copy void sendContinueUserSwitchLocked(UserStartedState uss, int oldUserId, int newUserId) {      mCurUserSwitchCallback = null;      mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);      mHandler.sendMessage(mHandler.obtainMessage(CONTINUE_USER_SWITCH_MSG,              oldUserId, newUserId, uss));  }  [java] view plain copy case CONTINUE_USER_SWITCH_MSG: {      continueUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);      break;  }  [java] view plain copy void continueUserSwitch(UserStartedState uss, int oldUserId, int newUserId) {      completeSwitchAndInitalize(uss, newUserId, false, true);  }  [java] view plain copy void completeSwitchAndInitalize(UserStartedState uss, int newUserId,          boolean clearInitializing, boolean clearSwitching) {      boolean unfrozen = false;      synchronized (this) {          if (clearInitializing) {              uss.initializing = false;              getUserManagerLocked().makeInitialized(uss.mHandle.getIdentifier());          }          if (clearSwitching) {              uss.switching = false;          }          if (!uss.switching && !uss.initializing) {              mWindowManager.stopFreezingScreen();              unfrozen = true;          }      }      if (unfrozen) {          final int N = mUserSwitchObservers.beginBroadcast();          for (int i=0; i<N; i++) {              try {                  mUserSwitchObservers.getBroadcastItem(i).onUserSwitchComplete(newUserId);              } catch (RemoteException e) {              }          }          mUserSwitchObservers.finishBroadcast();      }      stopGuestUserIfBackground();  }  CONTINUE_USER_SWITCH_MSG消息的處理方法是continueUserSwitch(),這個方法會調用completeSwitchAndInitalize()方法繼續處理,處理的結果是對mUserSwitchObservers列表中所有觀測對象調用他們的onUserSwitchComplete()方法。

至此,startUser()方法的工作就完成了。但是還有一個問題,狀態為STATE_BOOTING的用戶什么時候切換到STATE_RUNNING狀態?在activityIdleInternalLocked()方法中有一段代碼如下:

[java] view plain copy    for (int i = 0; i < startingUsers.size(); i++) {       mService.finishUserSwitch(startingUsers.get(i));    }  activityIdleInternalLocked()方法會在Activity進入Idle狀態時調用,也就相當于用戶已經切換完成了,會對每個startingUsers列表中的用戶調用finishUserBoot()方法,如下:[java] view plain copy void finishUserSwitch(UserStartedState uss) {      synchronized (this) {          finishUserBoot(uss);            startProfilesLocked();            int num = mUserLru.size();          int i = 0;          while (num > MAX_RUNNING_USERS && i < mUserLru.size()) {              Integer oldUserId = mUserLru.get(i);              UserStartedState oldUss = mStartedUsers.get(oldUserId);              if (oldUss == null) {//正常情況下不會出現為null                  // Shouldn't happen, but be sane if it does.                  mUserLru.remove(i);                  num--;                  continue;              }              if (oldUss.mState == UserStartedState.STATE_STOPPING                      || oldUss.mState == UserStartedState.STATE_SHUTDOWN) {                  // This user is already stopping, doesn't count.如果用戶已經停止了,繼續                  num--;                  i++;                  continue;              }              if (oldUserId == UserHandle.USER_OWNER || oldUserId == mCurrentUserId) {                  // Owner and current can't be stopped, but count as running.                  i++;//如果是主用戶或當前用戶,繼續                  continue;              }              // This is a user to be stopped.停止用戶              stopUserLocked(oldUserId, null);              num--;              i++;          }      }  }  finishUserSwitch()方法完成了兩件工作。一是調用方法finishUserBoot()把狀態還是STATE_BOOTING的用戶切換到STATE_RUNNING狀態,同時發送廣播ACTION_BOOT_COMPLETED給該用戶,表示用戶啟動結束。另一件工作是停止多余的用戶。從mUserLru列表的第0項開始,對于處于狀態STATE_RUNNING的用戶,只要不是主用戶或當前用戶,一律停止,只保留處于STATE_RUNNING狀態的用戶。

3、停止用戶運行

ActivityManagerService中停止用戶運行的接口是stopUser(),這個方法在檢查了調用進程的權限后,調用內部方法stopUserLocked()繼續停止用戶的工作,stopUserLocked()代碼如下:

[java] view plain copy private int stopUserLocked(final int userId, final IStopUserCallback callback) {      if (DEBUG_MU) Slog.i(TAG_MU, "stopUserLocked userId=" + userId);      if (mCurrentUserId == userId && mTargetUserId == UserHandle.USER_NULL) {          return ActivityManager.USER_OP_IS_CURRENT;      }//如果要求停止的用戶是當前用戶,不能停止,返回        final UserStartedState uss = mStartedUsers.get(userId);      if (uss == null) {          // User is not started, nothing to do...  but we do need to          // callback if requested.          if (callback != null) {              mHandler.post(new Runnable() {                  @Override                  public void run() {                      try {                          callback.userStopped(userId);//回調方法userStopped                      } catch (RemoteException e) {                      }                  }              });          }          return ActivityManager.USER_OP_SUCCESS;//0      }        if (callback != null) {          uss.mStopCallbacks.add(callback);      }        if (uss.mState != UserStartedState.STATE_STOPPING              && uss.mState != UserStartedState.STATE_SHUTDOWN) {          uss.mState = UserStartedState.STATE_STOPPING;//將用戶的狀態切換為正在停止          updateStartedUserArrayLocked();//更新mStartedUserArray數組,存放UserStartedState對象            long ident = Binder.clearCallingIdentity();          try {              // We are going to broadcast ACTION_USER_STOPPING and then              // once that is done send a final ACTION_SHUTDOWN and then              // stop the user.              final Intent stoppingIntent = new Intent(Intent.ACTION_USER_STOPPING);              stoppingIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);              stoppingIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);              stoppingIntent.putExtra(Intent.EXTRA_SHUTDOWN_USERSPACE_ONLY, true);              final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);              // This is the result receiver for the final shutdown broadcast.              final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {                  @Override                  public void performReceive(Intent intent, int resultCode, String data,                          Bundle extras, boolean ordered, boolean sticky, int sendingUser) {                      finishUserStop(uss);//收到ACTION_SHUTDOWN廣播,繼續執行                  }              };              // This is the result receiver for the initial stopping broadcast.              final IIntentReceiver stoppingReceiver = new IIntentReceiver.Stub() {                  @Override                  public void performReceive(Intent intent, int resultCode, String data,                          Bundle extras, boolean ordered, boolean sticky, int sendingUser) {                      // On to the next.                      synchronized (ActivityManagerService.this) {                          if (uss.mState != UserStartedState.STATE_STOPPING) {                              // Whoops, we are being started back up.  Abort, abort!                              return;                          }                          uss.mState = UserStartedState.STATE_SHUTDOWN;//收到ACTION_USER_STOPPING廣播后,改變用戶狀態                      }                      mBatteryStatsService.noteEvent(                              BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH,                              Integer.toString(userId), userId);                      mSystemServiceManager.stopUser(userId);                      broadcastIntentLocked(null, null, shutdownIntent,                              null, shutdownReceiver, 0, null, null, null, AppOpsManager.OP_NONE,                              true, false, MY_PID, Process.SYSTEM_UID, userId);//再發送廣播shutdownIntent(Intent.ACTION_SHUTDOWN)                  }              };              // Kick things off.              broadcastIntentLocked(null, null, stoppingIntent,                      null, stoppingReceiver, 0, null, null,                      INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE,                      true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);//發送廣播stoppingIntent(Intent.ACTION_USER_STOPPING)          } finally {              Binder.restoreCallingIdentity(ident);          }      }        return ActivityManager.USER_OP_SUCCESS;  }  stopUserLocked()方法首先判斷請求停止的用戶是否是當前用戶,是,返回。由此可見,當前正在運行的用戶是不能停止的,必須先切換到其他的用戶才能再停止該用戶。

接下來判斷用戶是否處于運行狀態,沒有運行就post一個消息,在消息的處理方法中調用參數中的回調方法結束處理。

如果用戶已經運行,先切換用戶的狀態為STATE_STOPPING,然后廣播一個用戶正在停止的消息ACTION_USER_STOPPING,同時方法中也會接收這個廣播,收到后切換用戶的狀態為STATE_SHUTDOWN,再發出一個ACTION_SHUTDOWN的廣播,方法中同樣也會接受這個廣播,收到后再調用finishUserStop()方法繼續處理,如下:

[java] view plain copy void finishUserStop(UserStartedState uss) {      final int userId = uss.mHandle.getIdentifier();      boolean stopped;      ArrayList<IStopUserCallback> callbacks;      synchronized (this) {          callbacks = new ArrayList<IStopUserCallback>(uss.mStopCallbacks);          if (mStartedUsers.get(userId) != uss) {              stopped = false;          } else if (uss.mState != UserStartedState.STATE_SHUTDOWN) {              stopped = false;          } else {              stopped = true;              // User can no longer run.從AMS的用戶管理的數據結構中刪除用戶              mStartedUsers.remove(userId);              mUserLru.remove(Integer.valueOf(userId));              updateStartedUserArrayLocked();                // Clean up all state and processes associated with the user.              // Kill all the processes for the user.              forceStopUserLocked(userId, "finish user");//發送廣播Intent.ACTION_USER_STOPPED          }            // Explicitly remove the old information in mRecentTasks.          removeRecentTasksForUserLocked(userId);//清除用戶相關的Recent Task列表      }        for (int i=0; i<callbacks.size(); i++) {          try {//調用UserManagerService的回調方法              if (stopped) callbacks.get(i).userStopped(userId);              else callbacks.get(i).userStopAborted(userId);          } catch (RemoteException e) {          }      }        if (stopped) {          mSystemServiceManager.cleanupUser(userId);//從mStackSupervisor刪除用戶          synchronized (this) {              mStackSupervisor.removeUserLocked(userId);          }      }  }  finishUserStop()方法的主要工作是從mStartedUsers和mUserLru中刪除用戶,然后發送廣播Intent.ACTION_USER_STOPPED來通知某個用戶停止了,接下來調用UserManagerService的回調方法通知UserManagerService來處理,最后調用removeUserLocked()方法從mStackSupervisor列表中刪除用戶的相關信息。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 修文县| 塔河县| 乌海市| 瓮安县| 读书| 彰化县| 阿巴嘎旗| 岚皋县| 福鼎市| 平果县| 黑河市| 正镶白旗| 庆元县| 运城市| 满洲里市| 涿州市| 宜兴市| 时尚| 尚义县| 红河县| 肇源县| 澜沧| 新郑市| 临朐县| 新平| 栖霞市| 道真| 大余县| 海兴县| 太仓市| 无棣县| 贺州市| 榕江县| 石渠县| 堆龙德庆县| 康马县| 东台市| 彭阳县| 宣恩县| 新竹县| 永济市|