14b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani/* 24b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * Copyright (C) 2011 The Android Open Source Project 34b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * 44b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * Licensed under the Apache License, Version 2.0 (the "License"); 54b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * you may not use this file except in compliance with the License. 64b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * You may obtain a copy of the License at 74b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * 84b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * http://www.apache.org/licenses/LICENSE-2.0 94b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * 104b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * Unless required by applicable law or agreed to in writing, software 114b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * distributed under the License is distributed on an "AS IS" BASIS, 124b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * See the License for the specific language governing permissions and 144b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * limitations under the License. 154b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani */ 164b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 174b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasanipackage com.android.server.pm; 184b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 19135936072b24b090fb63940aea41b408d855a4f3Amith Yamasaniimport com.android.internal.util.ArrayUtils; 204b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport com.android.internal.util.FastXmlSerializer; 214b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 220b285499db739ba50f2f839d633e763c70e67f96Amith Yamasaniimport android.content.pm.ApplicationInfo; 230b285499db739ba50f2f839d633e763c70e67f96Amith Yamasaniimport android.content.pm.PackageManager; 244b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport android.content.pm.UserInfo; 254b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport android.os.Environment; 264b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport android.os.FileUtils; 270b285499db739ba50f2f839d633e763c70e67f96Amith Yamasaniimport android.os.SystemClock; 28742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.os.UserId; 290b285499db739ba50f2f839d633e763c70e67f96Amith Yamasaniimport android.util.Log; 304b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport android.util.Slog; 314b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport android.util.SparseArray; 324b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport android.util.Xml; 334b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 344b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport java.io.BufferedOutputStream; 354b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport java.io.File; 364b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport java.io.FileInputStream; 374b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport java.io.FileOutputStream; 384b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport java.io.IOException; 394b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport java.util.ArrayList; 404b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport java.util.List; 414b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 424b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport org.xmlpull.v1.XmlPullParser; 434b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport org.xmlpull.v1.XmlPullParserException; 444b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport org.xmlpull.v1.XmlSerializer; 454b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 460b285499db739ba50f2f839d633e763c70e67f96Amith Yamasanipublic class UserManager { 474b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani private static final String TAG_NAME = "name"; 484b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 494b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani private static final String ATTR_FLAGS = "flags"; 504b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 514b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani private static final String ATTR_ID = "id"; 524b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 534b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani private static final String TAG_USERS = "users"; 544b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 554b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani private static final String TAG_USER = "user"; 564b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 570b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani private static final String LOG_TAG = "UserManager"; 584b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 590b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani private static final String USER_INFO_DIR = "system" + File.separator + "users"; 604b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani private static final String USER_LIST_FILENAME = "userlist.xml"; 614b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 62135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>(); 634b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 644b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani private final File mUsersDir; 654b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani private final File mUserListFile; 660b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani private int[] mUserIds; 670b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 680b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani private Installer mInstaller; 690b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani private File mBaseUserPath; 704b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 714b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani /** 724b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * Available for testing purposes. 734b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani */ 740b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani UserManager(File dataDir, File baseUserPath) { 754b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani mUsersDir = new File(dataDir, USER_INFO_DIR); 764b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani mUsersDir.mkdirs(); 77483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani // Make zeroth user directory, for services to migrate their files to that location 78483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani File userZeroDir = new File(mUsersDir, "0"); 79483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani userZeroDir.mkdirs(); 800b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani mBaseUserPath = baseUserPath; 814b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani FileUtils.setPermissions(mUsersDir.toString(), 824b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani FileUtils.S_IRWXU|FileUtils.S_IRWXG 834b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani |FileUtils.S_IROTH|FileUtils.S_IXOTH, 844b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani -1, -1); 854b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani mUserListFile = new File(mUsersDir, USER_LIST_FILENAME); 864b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani readUserList(); 874b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 884b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 890b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani public UserManager(Installer installer, File baseUserPath) { 900b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani this(Environment.getDataDirectory(), baseUserPath); 910b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani mInstaller = installer; 924b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 934b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 944b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani public List<UserInfo> getUsers() { 95135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani synchronized (mUsers) { 96135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size()); 97135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani for (int i = 0; i < mUsers.size(); i++) { 98135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani users.add(mUsers.valueAt(i)); 99135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 100135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani return users; 101135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 102135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 103135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani 104135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani public UserInfo getUser(int userId) { 105135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani synchronized (mUsers) { 106135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani UserInfo info = mUsers.get(userId); 107135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani return info; 108135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 109135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 110135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani 111135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani public boolean exists(int userId) { 112135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani synchronized (mUsers) { 113135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani return ArrayUtils.contains(mUserIds, userId); 114135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 115135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 116135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani 117135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani public void updateUserName(int userId, String name) { 118135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani synchronized (mUsers) { 119135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani UserInfo info = mUsers.get(userId); 120135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani if (name != null && !name.equals(info.name)) { 121135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani info.name = name; 122135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani writeUserLocked(info); 123135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 1244b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 1254b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 1264b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 1270b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani /** 1280b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani * Returns an array of user ids. This array is cached here for quick access, so do not modify or 1290b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani * cache it elsewhere. 1300b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani * @return the array of user ids. 1310b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani */ 1320b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani int[] getUserIds() { 1330b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani return mUserIds; 1340b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani } 1350b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 1364b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani private void readUserList() { 137135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani synchronized (mUsers) { 138135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani readUserListLocked(); 139135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 140135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 141135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani 142135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani private void readUserListLocked() { 1434b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani if (!mUserListFile.exists()) { 144135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani fallbackToSingleUserLocked(); 1454b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani return; 1464b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 1474b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani FileInputStream fis = null; 1484b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani try { 1494b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani fis = new FileInputStream(mUserListFile); 1504b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani XmlPullParser parser = Xml.newPullParser(); 1514b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani parser.setInput(fis, null); 1524b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani int type; 1534b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani while ((type = parser.next()) != XmlPullParser.START_TAG 1544b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani && type != XmlPullParser.END_DOCUMENT) { 1554b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani ; 1564b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 1574b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 1584b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani if (type != XmlPullParser.START_TAG) { 1590b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani Slog.e(LOG_TAG, "Unable to read user list"); 160135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani fallbackToSingleUserLocked(); 1614b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani return; 1624b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 1634b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 1644b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { 1654b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) { 1664b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani String id = parser.getAttributeValue(null, ATTR_ID); 1674b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani UserInfo user = readUser(Integer.parseInt(id)); 1684b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani if (user != null) { 1694b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani mUsers.put(user.id, user); 1704b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 1714b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 1724b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 173135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani updateUserIdsLocked(); 1744b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } catch (IOException ioe) { 175135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani fallbackToSingleUserLocked(); 1764b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } catch (XmlPullParserException pe) { 177135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani fallbackToSingleUserLocked(); 178bfd89b35bae3f679e1a219f22c07bde9eb63241bDianne Hackborn } finally { 179bfd89b35bae3f679e1a219f22c07bde9eb63241bDianne Hackborn if (fis != null) { 180bfd89b35bae3f679e1a219f22c07bde9eb63241bDianne Hackborn try { 181bfd89b35bae3f679e1a219f22c07bde9eb63241bDianne Hackborn fis.close(); 182bfd89b35bae3f679e1a219f22c07bde9eb63241bDianne Hackborn } catch (IOException e) { 183bfd89b35bae3f679e1a219f22c07bde9eb63241bDianne Hackborn } 184bfd89b35bae3f679e1a219f22c07bde9eb63241bDianne Hackborn } 1854b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 1864b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 1874b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 188135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani private void fallbackToSingleUserLocked() { 1894b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani // Create the primary user 1904b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani UserInfo primary = new UserInfo(0, "Primary", 1914b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY); 1924b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani mUsers.put(0, primary); 193135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani updateUserIdsLocked(); 1944b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 195135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani writeUserListLocked(); 196135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani writeUserLocked(primary); 1974b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 1984b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 1994b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani /* 2004b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * Writes the user file in this format: 2014b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * 2024b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * <user flags="20039023" id="0"> 2034b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * <name>Primary</name> 2044b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * </user> 2054b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani */ 206135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani private void writeUserLocked(UserInfo userInfo) { 207742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani FileOutputStream fos = null; 2084b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani try { 2094b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani final File mUserFile = new File(mUsersDir, userInfo.id + ".xml"); 210742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani fos = new FileOutputStream(mUserFile); 2114b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani final BufferedOutputStream bos = new BufferedOutputStream(fos); 2124b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 2134b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani // XmlSerializer serializer = XmlUtils.serializerInstance(); 2144b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani final XmlSerializer serializer = new FastXmlSerializer(); 2154b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.setOutput(bos, "utf-8"); 2164b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.startDocument(null, true); 2174b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 2184b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 2194b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.startTag(null, TAG_USER); 2204b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.attribute(null, ATTR_ID, Integer.toString(userInfo.id)); 2214b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.attribute(null, ATTR_FLAGS, Integer.toString(userInfo.flags)); 2224b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 2234b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.startTag(null, TAG_NAME); 2244b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.text(userInfo.name); 2254b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.endTag(null, TAG_NAME); 2264b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 2274b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.endTag(null, TAG_USER); 2284b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 2294b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.endDocument(); 2304b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } catch (IOException ioe) { 2310b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani Slog.e(LOG_TAG, "Error writing user info " + userInfo.id + "\n" + ioe); 232742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani } finally { 233742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani if (fos != null) { 234742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani try { 235742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani fos.close(); 236742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani } catch (IOException ioe) { 237742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani } 238742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani } 2394b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 2404b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 2414b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 2424b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani /* 2434b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * Writes the user list file in this format: 2444b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * 2454b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * <users> 2464b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * <user id="0"></user> 2474b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * <user id="2"></user> 2484b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * </users> 2494b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani */ 250135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani private void writeUserListLocked() { 251742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani FileOutputStream fos = null; 2524b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani try { 253742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani fos = new FileOutputStream(mUserListFile); 2544b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani final BufferedOutputStream bos = new BufferedOutputStream(fos); 2554b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 2564b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani // XmlSerializer serializer = XmlUtils.serializerInstance(); 2574b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani final XmlSerializer serializer = new FastXmlSerializer(); 2584b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.setOutput(bos, "utf-8"); 2594b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.startDocument(null, true); 2604b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 2614b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 2624b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.startTag(null, TAG_USERS); 2634b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 2644b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani for (int i = 0; i < mUsers.size(); i++) { 2654b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani UserInfo user = mUsers.valueAt(i); 2664b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.startTag(null, TAG_USER); 2674b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.attribute(null, ATTR_ID, Integer.toString(user.id)); 2684b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.endTag(null, TAG_USER); 2694b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 2704b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 2714b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.endTag(null, TAG_USERS); 2724b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 2734b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani serializer.endDocument(); 2744b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } catch (IOException ioe) { 2750b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani Slog.e(LOG_TAG, "Error writing user list"); 276742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani } finally { 277742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani if (fos != null) { 278742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani try { 279742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani fos.close(); 280742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani } catch (IOException ioe) { 281742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani } 282742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani } 2834b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 2844b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 2854b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 2864b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani private UserInfo readUser(int id) { 2874b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani int flags = 0; 2884b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani String name = null; 2894b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 2904b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani FileInputStream fis = null; 2914b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani try { 2924b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani File userFile = new File(mUsersDir, Integer.toString(id) + ".xml"); 2934b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani fis = new FileInputStream(userFile); 2944b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani XmlPullParser parser = Xml.newPullParser(); 2954b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani parser.setInput(fis, null); 2964b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani int type; 2974b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani while ((type = parser.next()) != XmlPullParser.START_TAG 2984b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani && type != XmlPullParser.END_DOCUMENT) { 2994b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani ; 3004b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 3014b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 3024b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani if (type != XmlPullParser.START_TAG) { 3030b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani Slog.e(LOG_TAG, "Unable to read user " + id); 3044b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani return null; 3054b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 3064b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 3074b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) { 3084b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani String storedId = parser.getAttributeValue(null, ATTR_ID); 3094b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani if (Integer.parseInt(storedId) != id) { 3100b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani Slog.e(LOG_TAG, "User id does not match the file name"); 3114b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani return null; 3124b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 3134b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani String flagString = parser.getAttributeValue(null, ATTR_FLAGS); 3144b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani flags = Integer.parseInt(flagString); 3154b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 3164b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani while ((type = parser.next()) != XmlPullParser.START_TAG 3174b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani && type != XmlPullParser.END_DOCUMENT) { 3184b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 3194b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_NAME)) { 3204b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani type = parser.next(); 3214b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani if (type == XmlPullParser.TEXT) { 3224b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani name = parser.getText(); 3234b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 3244b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 3254b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 3264b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 3274b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani UserInfo userInfo = new UserInfo(id, name, flags); 3284b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani return userInfo; 3294b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 3304b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } catch (IOException ioe) { 3314b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } catch (XmlPullParserException pe) { 332bfd89b35bae3f679e1a219f22c07bde9eb63241bDianne Hackborn } finally { 333bfd89b35bae3f679e1a219f22c07bde9eb63241bDianne Hackborn if (fis != null) { 334bfd89b35bae3f679e1a219f22c07bde9eb63241bDianne Hackborn try { 335bfd89b35bae3f679e1a219f22c07bde9eb63241bDianne Hackborn fis.close(); 336bfd89b35bae3f679e1a219f22c07bde9eb63241bDianne Hackborn } catch (IOException e) { 337bfd89b35bae3f679e1a219f22c07bde9eb63241bDianne Hackborn } 338bfd89b35bae3f679e1a219f22c07bde9eb63241bDianne Hackborn } 3394b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 3404b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani return null; 3414b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 3424b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 343135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani public UserInfo createUser(String name, int flags) { 3440b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani int userId = getNextAvailableId(); 3450b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani UserInfo userInfo = new UserInfo(userId, name, flags); 3460b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani File userPath = new File(mBaseUserPath, Integer.toString(userId)); 347135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani if (!createPackageFolders(userId, userPath)) { 3484b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani return null; 3494b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 350135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani synchronized (mUsers) { 351135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani mUsers.put(userId, userInfo); 352135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani writeUserListLocked(); 353135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani writeUserLocked(userInfo); 354135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani updateUserIdsLocked(); 355135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 3564b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani return userInfo; 3574b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 3584b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 3590b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani /** 3600b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani * Removes a user and all data directories created for that user. This method should be called 3610b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani * after the user's processes have been terminated. 3620b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani * @param id the user's id 3630b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani */ 364135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani public boolean removeUser(int id) { 365135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani synchronized (mUsers) { 366135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani return removeUserLocked(id); 367135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 368135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 369135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani 370135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani private boolean removeUserLocked(int id) { 3714b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani // Remove from the list 3724b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani UserInfo userInfo = mUsers.get(id); 3734b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani if (userInfo != null) { 3744b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani // Remove this user from the list 3754b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani mUsers.remove(id); 3764b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani // Remove user file 3774b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani File userFile = new File(mUsersDir, id + ".xml"); 3784b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani userFile.delete(); 3790b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani // Update the user list 380135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani writeUserListLocked(); 381135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani updateUserIdsLocked(); 382135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani return true; 3830b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani } 384135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani return false; 3850b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani } 3860b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 3870b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani public void installPackageForAllUsers(String packageName, int uid) { 3880b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani for (int userId : mUserIds) { 3890b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani // Don't do it for the primary user, it will become recursive. 3900b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani if (userId == 0) 3910b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani continue; 392742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani mInstaller.createUserData(packageName, UserId.getUid(userId, uid), 3930b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani userId); 3940b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani } 3950b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani } 3960b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 3970b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani public void clearUserDataForAllUsers(String packageName) { 3980b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani for (int userId : mUserIds) { 3990b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani // Don't do it for the primary user, it will become recursive. 4000b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani if (userId == 0) 4010b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani continue; 4020b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani mInstaller.clearUserData(packageName, userId); 4030b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani } 4040b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani } 4050b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 4060b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani public void removePackageForAllUsers(String packageName) { 4070b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani for (int userId : mUserIds) { 4080b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani // Don't do it for the primary user, it will become recursive. 4090b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani if (userId == 0) 4100b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani continue; 4110b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani mInstaller.remove(packageName, userId); 4120b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani } 4130b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani } 4140b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 4150b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani /** 4160b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani * Caches the list of user ids in an array, adjusting the array size when necessary. 4170b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani */ 418135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani private void updateUserIdsLocked() { 4190b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani if (mUserIds == null || mUserIds.length != mUsers.size()) { 4200b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani mUserIds = new int[mUsers.size()]; 4210b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani } 4220b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani for (int i = 0; i < mUsers.size(); i++) { 4230b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani mUserIds[i] = mUsers.keyAt(i); 4244b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 4254b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 4264b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 4270b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani /** 4280b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani * Returns the next available user id, filling in any holes in the ids. 429742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * TODO: May not be a good idea to recycle ids, in case it results in confusion 430742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * for data and battery stats collection, or unexpected cross-talk. 4310b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani * @return 4320b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani */ 4334b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani private int getNextAvailableId() { 4344b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani int i = 0; 4354b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani while (i < Integer.MAX_VALUE) { 4364b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani if (mUsers.indexOfKey(i) < 0) { 4374b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani break; 4384b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 4394b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani i++; 4404b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 4414b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani return i; 4424b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 4434b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 444135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani private boolean createPackageFolders(int id, File userPath) { 4450b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani // mInstaller may not be available for unit-tests. 446135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani if (mInstaller == null) return true; 4470b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 4480b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani // Create the user path 4490b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani userPath.mkdir(); 4500b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani FileUtils.setPermissions(userPath.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG 4510b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani | FileUtils.S_IXOTH, -1, -1); 4520b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 453742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani mInstaller.cloneUserData(0, id, false); 454742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani 4554b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani return true; 4564b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 4574b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 458135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani boolean removePackageFolders(int id) { 4590b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani // mInstaller may not be available for unit-tests. 4600b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani if (mInstaller == null) return true; 4610b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 4620b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani mInstaller.removeUserDataDirs(id); 4634b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani return true; 4644b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 4654b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani} 466