blob: 4f9375a6a95c6784614c66e8a55dac62ff9328e0 [file] [log] [blame]
Amith Yamasani4b2e9342011-03-31 12:38:53 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.pm;
18
Amith Yamasani13593602012-03-22 16:16:17 -070019import com.android.internal.util.ArrayUtils;
Amith Yamasani4b2e9342011-03-31 12:38:53 -070020import com.android.internal.util.FastXmlSerializer;
21
Amith Yamasani2a003292012-08-14 18:25:45 -070022import android.app.ActivityManager;
Dianne Hackborn80a4af22012-08-27 19:18:31 -070023import android.app.ActivityManagerNative;
24import android.app.IStopUserCallback;
Amith Yamasani258848d2012-08-10 17:06:33 -070025import android.content.Context;
26import android.content.Intent;
Amith Yamasani0b285492011-04-14 17:35:23 -070027import android.content.pm.PackageManager;
Amith Yamasani4b2e9342011-03-31 12:38:53 -070028import android.content.pm.UserInfo;
Amith Yamasanie928d7d2012-09-17 21:46:51 -070029import android.graphics.Bitmap;
30import android.graphics.BitmapFactory;
Amith Yamasani258848d2012-08-10 17:06:33 -070031import android.os.Binder;
Amith Yamasani4b2e9342011-03-31 12:38:53 -070032import android.os.Environment;
33import android.os.FileUtils;
Amith Yamasani258848d2012-08-10 17:06:33 -070034import android.os.IUserManager;
Amith Yamasani258848d2012-08-10 17:06:33 -070035import android.os.Process;
Dianne Hackborn80a4af22012-08-27 19:18:31 -070036import android.os.RemoteException;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070037import android.os.UserHandle;
Jeff Sharkey27bd34d2012-09-16 12:49:00 -070038import android.os.UserManager;
Amith Yamasani2a003292012-08-14 18:25:45 -070039import android.util.AtomicFile;
Amith Yamasani4b2e9342011-03-31 12:38:53 -070040import android.util.Slog;
41import android.util.SparseArray;
Amith Yamasani920ace02012-09-20 22:15:37 -070042import android.util.TimeUtils;
Amith Yamasani4b2e9342011-03-31 12:38:53 -070043import android.util.Xml;
44
45import java.io.BufferedOutputStream;
46import java.io.File;
Amith Yamasani920ace02012-09-20 22:15:37 -070047import java.io.FileDescriptor;
Amith Yamasani4b2e9342011-03-31 12:38:53 -070048import java.io.FileInputStream;
Amith Yamasanib8151ec2012-04-18 18:02:48 -070049import java.io.FileNotFoundException;
Amith Yamasani4b2e9342011-03-31 12:38:53 -070050import java.io.FileOutputStream;
51import java.io.IOException;
Amith Yamasani920ace02012-09-20 22:15:37 -070052import java.io.PrintWriter;
Amith Yamasani4b2e9342011-03-31 12:38:53 -070053import java.util.ArrayList;
Amith Yamasani920ace02012-09-20 22:15:37 -070054import java.util.HashSet;
Amith Yamasani4b2e9342011-03-31 12:38:53 -070055import java.util.List;
56
57import org.xmlpull.v1.XmlPullParser;
58import org.xmlpull.v1.XmlPullParserException;
59import org.xmlpull.v1.XmlSerializer;
60
Amith Yamasani258848d2012-08-10 17:06:33 -070061public class UserManagerService extends IUserManager.Stub {
Amith Yamasanib8151ec2012-04-18 18:02:48 -070062
Amith Yamasani2a003292012-08-14 18:25:45 -070063 private static final String LOG_TAG = "UserManagerService";
Amith Yamasanib8151ec2012-04-18 18:02:48 -070064
Amith Yamasani4b2e9342011-03-31 12:38:53 -070065 private static final String TAG_NAME = "name";
Amith Yamasani4b2e9342011-03-31 12:38:53 -070066 private static final String ATTR_FLAGS = "flags";
Amith Yamasanib8151ec2012-04-18 18:02:48 -070067 private static final String ATTR_ICON_PATH = "icon";
Amith Yamasani4b2e9342011-03-31 12:38:53 -070068 private static final String ATTR_ID = "id";
Amith Yamasani920ace02012-09-20 22:15:37 -070069 private static final String ATTR_CREATION_TIME = "created";
70 private static final String ATTR_LAST_LOGGED_IN_TIME = "lastLoggedIn";
Amith Yamasani2a003292012-08-14 18:25:45 -070071 private static final String ATTR_SERIAL_NO = "serialNumber";
72 private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -070073 private static final String ATTR_PARTIAL = "partial";
Amith Yamasani4b2e9342011-03-31 12:38:53 -070074 private static final String TAG_USERS = "users";
Amith Yamasani4b2e9342011-03-31 12:38:53 -070075 private static final String TAG_USER = "user";
76
Amith Yamasani0b285492011-04-14 17:35:23 -070077 private static final String USER_INFO_DIR = "system" + File.separator + "users";
Amith Yamasani4b2e9342011-03-31 12:38:53 -070078 private static final String USER_LIST_FILENAME = "userlist.xml";
Amith Yamasanib8151ec2012-04-18 18:02:48 -070079 private static final String USER_PHOTO_FILENAME = "photo.png";
Amith Yamasani4b2e9342011-03-31 12:38:53 -070080
Amith Yamasani634cf312012-10-04 17:34:21 -070081 private static final int MIN_USER_ID = 10;
82
Amith Yamasani920ace02012-09-20 22:15:37 -070083 private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
84
Dianne Hackborn4428e172012-08-24 17:43:05 -070085 private final Context mContext;
86 private final PackageManagerService mPm;
87 private final Object mInstallLock;
88 private final Object mPackagesLock;
Amith Yamasani4b2e9342011-03-31 12:38:53 -070089
90 private final File mUsersDir;
91 private final File mUserListFile;
Dianne Hackborn4428e172012-08-24 17:43:05 -070092 private final File mBaseUserPath;
93
94 private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
Amith Yamasani920ace02012-09-20 22:15:37 -070095 private HashSet<Integer> mRemovingUserIds = new HashSet<Integer>();
Dianne Hackborn4428e172012-08-24 17:43:05 -070096
Amith Yamasani0b285492011-04-14 17:35:23 -070097 private int[] mUserIds;
Amith Yamasani258848d2012-08-10 17:06:33 -070098 private boolean mGuestEnabled;
Amith Yamasani2a003292012-08-14 18:25:45 -070099 private int mNextSerialNumber;
Amith Yamasani0b285492011-04-14 17:35:23 -0700100
Amith Yamasani258848d2012-08-10 17:06:33 -0700101 private static UserManagerService sInstance;
Amith Yamasani258848d2012-08-10 17:06:33 -0700102
Dianne Hackborn4428e172012-08-24 17:43:05 -0700103 public static UserManagerService getInstance() {
104 synchronized (UserManagerService.class) {
105 return sInstance;
Amith Yamasani258848d2012-08-10 17:06:33 -0700106 }
Amith Yamasani258848d2012-08-10 17:06:33 -0700107 }
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700108
109 /**
110 * Available for testing purposes.
111 */
Amith Yamasani258848d2012-08-10 17:06:33 -0700112 UserManagerService(File dataDir, File baseUserPath) {
Dianne Hackborn4428e172012-08-24 17:43:05 -0700113 this(null, null, new Object(), new Object(), dataDir, baseUserPath);
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700114 }
115
Dianne Hackborn4428e172012-08-24 17:43:05 -0700116 /**
117 * Called by package manager to create the service. This is closely
118 * associated with the package manager, and the given lock is the
119 * package manager's own lock.
120 */
121 UserManagerService(Context context, PackageManagerService pm,
122 Object installLock, Object packagesLock) {
123 this(context, pm, installLock, packagesLock,
124 Environment.getDataDirectory(),
125 new File(Environment.getDataDirectory(), "user"));
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700126 }
127
Dianne Hackborn4428e172012-08-24 17:43:05 -0700128 /**
129 * Available for testing purposes.
130 */
131 private UserManagerService(Context context, PackageManagerService pm,
132 Object installLock, Object packagesLock,
133 File dataDir, File baseUserPath) {
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700134 mContext = context;
135 mPm = pm;
136 mInstallLock = installLock;
137 mPackagesLock = packagesLock;
138 synchronized (mInstallLock) {
139 synchronized (mPackagesLock) {
140 mUsersDir = new File(dataDir, USER_INFO_DIR);
141 mUsersDir.mkdirs();
142 // Make zeroth user directory, for services to migrate their files to that location
143 File userZeroDir = new File(mUsersDir, "0");
144 userZeroDir.mkdirs();
145 mBaseUserPath = baseUserPath;
146 FileUtils.setPermissions(mUsersDir.toString(),
147 FileUtils.S_IRWXU|FileUtils.S_IRWXG
148 |FileUtils.S_IROTH|FileUtils.S_IXOTH,
149 -1, -1);
150 mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
151 readUserListLocked();
152 // Prune out any partially created users.
153 ArrayList<UserInfo> partials = new ArrayList<UserInfo>();
154 for (int i = 0; i < mUsers.size(); i++) {
155 UserInfo ui = mUsers.valueAt(i);
156 if (ui.partial && i != 0) {
157 partials.add(ui);
158 }
159 }
160 for (int i = 0; i < partials.size(); i++) {
161 UserInfo ui = partials.get(i);
162 Slog.w(LOG_TAG, "Removing partially created user #" + i
163 + " (name=" + ui.name + ")");
164 removeUserStateLocked(ui.id);
165 }
166 sInstance = this;
167 }
Dianne Hackborn4428e172012-08-24 17:43:05 -0700168 }
Amith Yamasani258848d2012-08-10 17:06:33 -0700169 }
170
171 @Override
Amith Yamasani920ace02012-09-20 22:15:37 -0700172 public List<UserInfo> getUsers(boolean excludeDying) {
Amith Yamasani2a003292012-08-14 18:25:45 -0700173 checkManageUsersPermission("query users");
Dianne Hackborn4428e172012-08-24 17:43:05 -0700174 synchronized (mPackagesLock) {
Amith Yamasani13593602012-03-22 16:16:17 -0700175 ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
176 for (int i = 0; i < mUsers.size(); i++) {
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700177 UserInfo ui = mUsers.valueAt(i);
178 if (ui.partial) {
179 continue;
180 }
181 if (!excludeDying || !mRemovingUserIds.contains(ui.id)) {
182 users.add(ui);
Amith Yamasani920ace02012-09-20 22:15:37 -0700183 }
Amith Yamasani13593602012-03-22 16:16:17 -0700184 }
185 return users;
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700186 }
Amith Yamasani13593602012-03-22 16:16:17 -0700187 }
188
Amith Yamasani258848d2012-08-10 17:06:33 -0700189 @Override
190 public UserInfo getUserInfo(int userId) {
Amith Yamasani2a003292012-08-14 18:25:45 -0700191 checkManageUsersPermission("query user");
Dianne Hackborn4428e172012-08-24 17:43:05 -0700192 synchronized (mPackagesLock) {
Amith Yamasani195263742012-08-21 15:40:12 -0700193 return getUserInfoLocked(userId);
Amith Yamasani13593602012-03-22 16:16:17 -0700194 }
195 }
196
Amith Yamasani195263742012-08-21 15:40:12 -0700197 /*
198 * Should be locked on mUsers before calling this.
199 */
200 private UserInfo getUserInfoLocked(int userId) {
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700201 UserInfo ui = mUsers.get(userId);
202 if (ui != null && ui.partial) {
203 Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId);
204 return null;
205 }
206 return ui;
Amith Yamasani195263742012-08-21 15:40:12 -0700207 }
208
Amith Yamasani13593602012-03-22 16:16:17 -0700209 public boolean exists(int userId) {
Dianne Hackborn4428e172012-08-24 17:43:05 -0700210 synchronized (mPackagesLock) {
Amith Yamasani13593602012-03-22 16:16:17 -0700211 return ArrayUtils.contains(mUserIds, userId);
212 }
213 }
214
Amith Yamasani258848d2012-08-10 17:06:33 -0700215 @Override
Amith Yamasanib8151ec2012-04-18 18:02:48 -0700216 public void setUserName(int userId, String name) {
Amith Yamasani2a003292012-08-14 18:25:45 -0700217 checkManageUsersPermission("rename users");
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700218 boolean changed = false;
Dianne Hackborn4428e172012-08-24 17:43:05 -0700219 synchronized (mPackagesLock) {
Amith Yamasani13593602012-03-22 16:16:17 -0700220 UserInfo info = mUsers.get(userId);
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700221 if (info == null || info.partial) {
222 Slog.w(LOG_TAG, "setUserName: unknown user #" + userId);
223 return;
224 }
Amith Yamasani13593602012-03-22 16:16:17 -0700225 if (name != null && !name.equals(info.name)) {
226 info.name = name;
227 writeUserLocked(info);
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700228 changed = true;
Amith Yamasani13593602012-03-22 16:16:17 -0700229 }
230 }
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700231 if (changed) {
232 sendUserInfoChangedBroadcast(userId);
233 }
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700234 }
235
Amith Yamasani258848d2012-08-10 17:06:33 -0700236 @Override
Amith Yamasanie928d7d2012-09-17 21:46:51 -0700237 public void setUserIcon(int userId, Bitmap bitmap) {
Amith Yamasani2a003292012-08-14 18:25:45 -0700238 checkManageUsersPermission("update users");
Dianne Hackborn4428e172012-08-24 17:43:05 -0700239 synchronized (mPackagesLock) {
Amith Yamasanib8151ec2012-04-18 18:02:48 -0700240 UserInfo info = mUsers.get(userId);
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700241 if (info == null || info.partial) {
242 Slog.w(LOG_TAG, "setUserIcon: unknown user #" + userId);
243 return;
244 }
Amith Yamasanie928d7d2012-09-17 21:46:51 -0700245 writeBitmapLocked(info, bitmap);
246 writeUserLocked(info);
Amith Yamasanib8151ec2012-04-18 18:02:48 -0700247 }
Amith Yamasanie928d7d2012-09-17 21:46:51 -0700248 sendUserInfoChangedBroadcast(userId);
249 }
250
251 private void sendUserInfoChangedBroadcast(int userId) {
252 Intent changedIntent = new Intent(Intent.ACTION_USER_INFO_CHANGED);
253 changedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
254 changedIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
255 mContext.sendBroadcastAsUser(changedIntent, new UserHandle(userId));
Amith Yamasanib8151ec2012-04-18 18:02:48 -0700256 }
257
Amith Yamasani258848d2012-08-10 17:06:33 -0700258 @Override
Amith Yamasanie928d7d2012-09-17 21:46:51 -0700259 public Bitmap getUserIcon(int userId) {
Amith Yamasani3b49f072012-09-17 10:21:43 -0700260 checkManageUsersPermission("read users");
261 synchronized (mPackagesLock) {
262 UserInfo info = mUsers.get(userId);
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700263 if (info == null || info.partial) {
264 Slog.w(LOG_TAG, "getUserIcon: unknown user #" + userId);
265 return null;
266 }
267 if (info.iconPath == null) {
268 return null;
269 }
Amith Yamasanie928d7d2012-09-17 21:46:51 -0700270 return BitmapFactory.decodeFile(info.iconPath);
Amith Yamasani3b49f072012-09-17 10:21:43 -0700271 }
272 }
273
274 @Override
Amith Yamasani258848d2012-08-10 17:06:33 -0700275 public void setGuestEnabled(boolean enable) {
Amith Yamasani2a003292012-08-14 18:25:45 -0700276 checkManageUsersPermission("enable guest users");
Dianne Hackborn4428e172012-08-24 17:43:05 -0700277 synchronized (mPackagesLock) {
Amith Yamasani258848d2012-08-10 17:06:33 -0700278 if (mGuestEnabled != enable) {
279 mGuestEnabled = enable;
280 // Erase any guest user that currently exists
281 for (int i = 0; i < mUsers.size(); i++) {
282 UserInfo user = mUsers.valueAt(i);
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700283 if (!user.partial && user.isGuest()) {
Amith Yamasani258848d2012-08-10 17:06:33 -0700284 if (!enable) {
285 removeUser(user.id);
286 }
287 return;
288 }
289 }
290 // No guest was found
291 if (enable) {
292 createUser("Guest", UserInfo.FLAG_GUEST);
293 }
294 }
295 }
296 }
297
298 @Override
299 public boolean isGuestEnabled() {
Dianne Hackborn4428e172012-08-24 17:43:05 -0700300 synchronized (mPackagesLock) {
Amith Yamasani258848d2012-08-10 17:06:33 -0700301 return mGuestEnabled;
302 }
303 }
304
305 @Override
306 public void wipeUser(int userHandle) {
Amith Yamasani2a003292012-08-14 18:25:45 -0700307 checkManageUsersPermission("wipe user");
Amith Yamasani258848d2012-08-10 17:06:33 -0700308 // TODO:
309 }
310
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700311 public void makeInitialized(int userId) {
312 checkManageUsersPermission("makeInitialized");
313 synchronized (mPackagesLock) {
314 UserInfo info = mUsers.get(userId);
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700315 if (info == null || info.partial) {
316 Slog.w(LOG_TAG, "makeInitialized: unknown user #" + userId);
317 }
318 if ((info.flags&UserInfo.FLAG_INITIALIZED) == 0) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700319 info.flags |= UserInfo.FLAG_INITIALIZED;
320 writeUserLocked(info);
321 }
322 }
323 }
324
Amith Yamasani258848d2012-08-10 17:06:33 -0700325 /**
Amith Yamasanifaea76f2012-09-11 10:59:48 -0700326 * Check if we've hit the limit of how many users can be created.
327 */
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700328 private boolean isUserLimitReachedLocked() {
329 int nUsers = mUsers.size();
Jeff Sharkey27bd34d2012-09-16 12:49:00 -0700330 return nUsers >= UserManager.getMaxSupportedUsers();
Amith Yamasanifaea76f2012-09-11 10:59:48 -0700331 }
332
333 /**
Amith Yamasani195263742012-08-21 15:40:12 -0700334 * Enforces that only the system UID or root's UID or apps that have the
335 * {@link android.Manifest.permission.MANAGE_USERS MANAGE_USERS}
336 * permission can make certain calls to the UserManager.
Amith Yamasani258848d2012-08-10 17:06:33 -0700337 *
338 * @param message used as message if SecurityException is thrown
339 * @throws SecurityException if the caller is not system or root
340 */
Amith Yamasani2a003292012-08-14 18:25:45 -0700341 private static final void checkManageUsersPermission(String message) {
Amith Yamasani258848d2012-08-10 17:06:33 -0700342 final int uid = Binder.getCallingUid();
Amith Yamasani2a003292012-08-14 18:25:45 -0700343 if (uid != Process.SYSTEM_UID && uid != 0
344 && ActivityManager.checkComponentPermission(
345 android.Manifest.permission.MANAGE_USERS,
346 uid, -1, true) != PackageManager.PERMISSION_GRANTED) {
347 throw new SecurityException("You need MANAGE_USERS permission to: " + message);
Amith Yamasani258848d2012-08-10 17:06:33 -0700348 }
349 }
350
Amith Yamasanie928d7d2012-09-17 21:46:51 -0700351 private void writeBitmapLocked(UserInfo info, Bitmap bitmap) {
Amith Yamasanib8151ec2012-04-18 18:02:48 -0700352 try {
353 File dir = new File(mUsersDir, Integer.toString(info.id));
354 File file = new File(dir, USER_PHOTO_FILENAME);
355 if (!dir.exists()) {
356 dir.mkdir();
357 FileUtils.setPermissions(
358 dir.getPath(),
359 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
360 -1, -1);
361 }
Amith Yamasanie928d7d2012-09-17 21:46:51 -0700362 FileOutputStream os;
363 if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, os = new FileOutputStream(file))) {
Amith Yamasani3b49f072012-09-17 10:21:43 -0700364 info.iconPath = file.getAbsolutePath();
365 }
Amith Yamasanie928d7d2012-09-17 21:46:51 -0700366 try {
367 os.close();
368 } catch (IOException ioe) {
369 // What the ... !
370 }
Amith Yamasanib8151ec2012-04-18 18:02:48 -0700371 } catch (FileNotFoundException e) {
Amith Yamasani2a003292012-08-14 18:25:45 -0700372 Slog.w(LOG_TAG, "Error setting photo for user ", e);
Amith Yamasanib8151ec2012-04-18 18:02:48 -0700373 }
Amith Yamasanib8151ec2012-04-18 18:02:48 -0700374 }
375
Amith Yamasani0b285492011-04-14 17:35:23 -0700376 /**
377 * Returns an array of user ids. This array is cached here for quick access, so do not modify or
378 * cache it elsewhere.
379 * @return the array of user ids.
380 */
Dianne Hackborn1676c852012-09-10 14:52:30 -0700381 public int[] getUserIds() {
Dianne Hackborn4428e172012-08-24 17:43:05 -0700382 synchronized (mPackagesLock) {
Dianne Hackborn7767eac2012-08-23 18:25:40 -0700383 return mUserIds;
384 }
Amith Yamasani0b285492011-04-14 17:35:23 -0700385 }
386
Dianne Hackborn4428e172012-08-24 17:43:05 -0700387 int[] getUserIdsLPr() {
388 return mUserIds;
389 }
390
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700391 private void readUserList() {
Dianne Hackborn4428e172012-08-24 17:43:05 -0700392 synchronized (mPackagesLock) {
Amith Yamasani13593602012-03-22 16:16:17 -0700393 readUserListLocked();
394 }
395 }
396
397 private void readUserListLocked() {
Amith Yamasani258848d2012-08-10 17:06:33 -0700398 mGuestEnabled = false;
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700399 if (!mUserListFile.exists()) {
Amith Yamasani13593602012-03-22 16:16:17 -0700400 fallbackToSingleUserLocked();
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700401 return;
402 }
403 FileInputStream fis = null;
Amith Yamasani2a003292012-08-14 18:25:45 -0700404 AtomicFile userListFile = new AtomicFile(mUserListFile);
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700405 try {
Amith Yamasani2a003292012-08-14 18:25:45 -0700406 fis = userListFile.openRead();
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700407 XmlPullParser parser = Xml.newPullParser();
408 parser.setInput(fis, null);
409 int type;
410 while ((type = parser.next()) != XmlPullParser.START_TAG
411 && type != XmlPullParser.END_DOCUMENT) {
412 ;
413 }
414
415 if (type != XmlPullParser.START_TAG) {
Amith Yamasani0b285492011-04-14 17:35:23 -0700416 Slog.e(LOG_TAG, "Unable to read user list");
Amith Yamasani13593602012-03-22 16:16:17 -0700417 fallbackToSingleUserLocked();
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700418 return;
419 }
420
Amith Yamasani2a003292012-08-14 18:25:45 -0700421 mNextSerialNumber = -1;
422 if (parser.getName().equals(TAG_USERS)) {
423 String lastSerialNumber = parser.getAttributeValue(null, ATTR_NEXT_SERIAL_NO);
424 if (lastSerialNumber != null) {
425 mNextSerialNumber = Integer.parseInt(lastSerialNumber);
426 }
427 }
428
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700429 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
430 if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) {
431 String id = parser.getAttributeValue(null, ATTR_ID);
432 UserInfo user = readUser(Integer.parseInt(id));
433 if (user != null) {
434 mUsers.put(user.id, user);
Amith Yamasani2a003292012-08-14 18:25:45 -0700435 if (user.isGuest()) {
436 mGuestEnabled = true;
437 }
438 if (mNextSerialNumber < 0 || mNextSerialNumber <= user.id) {
439 mNextSerialNumber = user.id + 1;
440 }
Amith Yamasani258848d2012-08-10 17:06:33 -0700441 }
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700442 }
443 }
Amith Yamasani13593602012-03-22 16:16:17 -0700444 updateUserIdsLocked();
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700445 } catch (IOException ioe) {
Amith Yamasani13593602012-03-22 16:16:17 -0700446 fallbackToSingleUserLocked();
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700447 } catch (XmlPullParserException pe) {
Amith Yamasani13593602012-03-22 16:16:17 -0700448 fallbackToSingleUserLocked();
Dianne Hackbornbfd89b32011-12-15 18:22:54 -0800449 } finally {
450 if (fis != null) {
451 try {
452 fis.close();
453 } catch (IOException e) {
454 }
455 }
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700456 }
457 }
458
Amith Yamasani13593602012-03-22 16:16:17 -0700459 private void fallbackToSingleUserLocked() {
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700460 // Create the primary user
Amith Yamasanib8151ec2012-04-18 18:02:48 -0700461 UserInfo primary = new UserInfo(0, "Primary", null,
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700462 UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
463 mUsers.put(0, primary);
Amith Yamasani634cf312012-10-04 17:34:21 -0700464 mNextSerialNumber = MIN_USER_ID;
Amith Yamasani13593602012-03-22 16:16:17 -0700465 updateUserIdsLocked();
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700466
Amith Yamasani13593602012-03-22 16:16:17 -0700467 writeUserListLocked();
468 writeUserLocked(primary);
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700469 }
470
471 /*
472 * Writes the user file in this format:
473 *
474 * <user flags="20039023" id="0">
475 * <name>Primary</name>
476 * </user>
477 */
Amith Yamasani13593602012-03-22 16:16:17 -0700478 private void writeUserLocked(UserInfo userInfo) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700479 FileOutputStream fos = null;
Amith Yamasani2a003292012-08-14 18:25:45 -0700480 AtomicFile userFile = new AtomicFile(new File(mUsersDir, userInfo.id + ".xml"));
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700481 try {
Amith Yamasani2a003292012-08-14 18:25:45 -0700482 fos = userFile.startWrite();
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700483 final BufferedOutputStream bos = new BufferedOutputStream(fos);
484
485 // XmlSerializer serializer = XmlUtils.serializerInstance();
486 final XmlSerializer serializer = new FastXmlSerializer();
487 serializer.setOutput(bos, "utf-8");
488 serializer.startDocument(null, true);
489 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
490
491 serializer.startTag(null, TAG_USER);
492 serializer.attribute(null, ATTR_ID, Integer.toString(userInfo.id));
Amith Yamasani2a003292012-08-14 18:25:45 -0700493 serializer.attribute(null, ATTR_SERIAL_NO, Integer.toString(userInfo.serialNumber));
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700494 serializer.attribute(null, ATTR_FLAGS, Integer.toString(userInfo.flags));
Amith Yamasani920ace02012-09-20 22:15:37 -0700495 serializer.attribute(null, ATTR_CREATION_TIME, Long.toString(userInfo.creationTime));
496 serializer.attribute(null, ATTR_LAST_LOGGED_IN_TIME,
497 Long.toString(userInfo.lastLoggedInTime));
Amith Yamasanib8151ec2012-04-18 18:02:48 -0700498 if (userInfo.iconPath != null) {
499 serializer.attribute(null, ATTR_ICON_PATH, userInfo.iconPath);
500 }
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700501 if (userInfo.partial) {
502 serializer.attribute(null, ATTR_PARTIAL, "true");
503 }
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700504
505 serializer.startTag(null, TAG_NAME);
506 serializer.text(userInfo.name);
507 serializer.endTag(null, TAG_NAME);
508
509 serializer.endTag(null, TAG_USER);
510
511 serializer.endDocument();
Amith Yamasani2a003292012-08-14 18:25:45 -0700512 userFile.finishWrite(fos);
513 } catch (Exception ioe) {
Amith Yamasani0b285492011-04-14 17:35:23 -0700514 Slog.e(LOG_TAG, "Error writing user info " + userInfo.id + "\n" + ioe);
Amith Yamasani2a003292012-08-14 18:25:45 -0700515 userFile.failWrite(fos);
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700516 }
517 }
518
519 /*
520 * Writes the user list file in this format:
521 *
Amith Yamasani2a003292012-08-14 18:25:45 -0700522 * <users nextSerialNumber="3">
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700523 * <user id="0"></user>
524 * <user id="2"></user>
525 * </users>
526 */
Amith Yamasani13593602012-03-22 16:16:17 -0700527 private void writeUserListLocked() {
Amith Yamasani742a6712011-05-04 14:49:28 -0700528 FileOutputStream fos = null;
Amith Yamasani2a003292012-08-14 18:25:45 -0700529 AtomicFile userListFile = new AtomicFile(mUserListFile);
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700530 try {
Amith Yamasani2a003292012-08-14 18:25:45 -0700531 fos = userListFile.startWrite();
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700532 final BufferedOutputStream bos = new BufferedOutputStream(fos);
533
534 // XmlSerializer serializer = XmlUtils.serializerInstance();
535 final XmlSerializer serializer = new FastXmlSerializer();
536 serializer.setOutput(bos, "utf-8");
537 serializer.startDocument(null, true);
538 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
539
540 serializer.startTag(null, TAG_USERS);
Amith Yamasani2a003292012-08-14 18:25:45 -0700541 serializer.attribute(null, ATTR_NEXT_SERIAL_NO, Integer.toString(mNextSerialNumber));
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700542
543 for (int i = 0; i < mUsers.size(); i++) {
544 UserInfo user = mUsers.valueAt(i);
545 serializer.startTag(null, TAG_USER);
546 serializer.attribute(null, ATTR_ID, Integer.toString(user.id));
547 serializer.endTag(null, TAG_USER);
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700548 }
549
550 serializer.endTag(null, TAG_USERS);
551
552 serializer.endDocument();
Amith Yamasani2a003292012-08-14 18:25:45 -0700553 userListFile.finishWrite(fos);
554 } catch (Exception e) {
555 userListFile.failWrite(fos);
Amith Yamasani0b285492011-04-14 17:35:23 -0700556 Slog.e(LOG_TAG, "Error writing user list");
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700557 }
558 }
559
560 private UserInfo readUser(int id) {
561 int flags = 0;
Amith Yamasani2a003292012-08-14 18:25:45 -0700562 int serialNumber = id;
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700563 String name = null;
Amith Yamasanib8151ec2012-04-18 18:02:48 -0700564 String iconPath = null;
Amith Yamasani920ace02012-09-20 22:15:37 -0700565 long creationTime = 0L;
566 long lastLoggedInTime = 0L;
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700567 boolean partial = false;
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700568
569 FileInputStream fis = null;
570 try {
Amith Yamasani2a003292012-08-14 18:25:45 -0700571 AtomicFile userFile =
572 new AtomicFile(new File(mUsersDir, Integer.toString(id) + ".xml"));
573 fis = userFile.openRead();
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700574 XmlPullParser parser = Xml.newPullParser();
575 parser.setInput(fis, null);
576 int type;
577 while ((type = parser.next()) != XmlPullParser.START_TAG
578 && type != XmlPullParser.END_DOCUMENT) {
579 ;
580 }
581
582 if (type != XmlPullParser.START_TAG) {
Amith Yamasani0b285492011-04-14 17:35:23 -0700583 Slog.e(LOG_TAG, "Unable to read user " + id);
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700584 return null;
585 }
586
587 if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) {
Amith Yamasani920ace02012-09-20 22:15:37 -0700588 int storedId = readIntAttribute(parser, ATTR_ID, -1);
589 if (storedId != id) {
Amith Yamasani0b285492011-04-14 17:35:23 -0700590 Slog.e(LOG_TAG, "User id does not match the file name");
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700591 return null;
592 }
Amith Yamasani920ace02012-09-20 22:15:37 -0700593 serialNumber = readIntAttribute(parser, ATTR_SERIAL_NO, id);
594 flags = readIntAttribute(parser, ATTR_FLAGS, 0);
Amith Yamasanib8151ec2012-04-18 18:02:48 -0700595 iconPath = parser.getAttributeValue(null, ATTR_ICON_PATH);
Amith Yamasani920ace02012-09-20 22:15:37 -0700596 creationTime = readLongAttribute(parser, ATTR_CREATION_TIME, 0);
597 lastLoggedInTime = readLongAttribute(parser, ATTR_LAST_LOGGED_IN_TIME, 0);
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700598 String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);
599 if ("true".equals(valueString)) {
600 partial = true;
601 }
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700602
603 while ((type = parser.next()) != XmlPullParser.START_TAG
604 && type != XmlPullParser.END_DOCUMENT) {
605 }
606 if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_NAME)) {
607 type = parser.next();
608 if (type == XmlPullParser.TEXT) {
609 name = parser.getText();
610 }
611 }
612 }
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700613
Amith Yamasanib8151ec2012-04-18 18:02:48 -0700614 UserInfo userInfo = new UserInfo(id, name, iconPath, flags);
Amith Yamasani2a003292012-08-14 18:25:45 -0700615 userInfo.serialNumber = serialNumber;
Amith Yamasani920ace02012-09-20 22:15:37 -0700616 userInfo.creationTime = creationTime;
617 userInfo.lastLoggedInTime = lastLoggedInTime;
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700618 userInfo.partial = partial;
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700619 return userInfo;
620
621 } catch (IOException ioe) {
622 } catch (XmlPullParserException pe) {
Dianne Hackbornbfd89b32011-12-15 18:22:54 -0800623 } finally {
624 if (fis != null) {
625 try {
626 fis.close();
627 } catch (IOException e) {
628 }
629 }
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700630 }
631 return null;
632 }
633
Amith Yamasani920ace02012-09-20 22:15:37 -0700634 private int readIntAttribute(XmlPullParser parser, String attr, int defaultValue) {
635 String valueString = parser.getAttributeValue(null, attr);
636 if (valueString == null) return defaultValue;
637 try {
638 return Integer.parseInt(valueString);
639 } catch (NumberFormatException nfe) {
640 return defaultValue;
641 }
642 }
643
644 private long readLongAttribute(XmlPullParser parser, String attr, long defaultValue) {
645 String valueString = parser.getAttributeValue(null, attr);
646 if (valueString == null) return defaultValue;
647 try {
648 return Long.parseLong(valueString);
649 } catch (NumberFormatException nfe) {
650 return defaultValue;
651 }
652 }
653
Amith Yamasani258848d2012-08-10 17:06:33 -0700654 @Override
Amith Yamasani13593602012-03-22 16:16:17 -0700655 public UserInfo createUser(String name, int flags) {
Amith Yamasani2a003292012-08-14 18:25:45 -0700656 checkManageUsersPermission("Only the system can create users");
Amith Yamasanifaea76f2012-09-11 10:59:48 -0700657
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700658 final long ident = Binder.clearCallingIdentity();
659 final UserInfo userInfo;
660 try {
661 synchronized (mInstallLock) {
662 synchronized (mPackagesLock) {
663 if (isUserLimitReachedLocked()) return null;
664 int userId = getNextAvailableIdLocked();
665 userInfo = new UserInfo(userId, name, null, flags);
666 File userPath = new File(mBaseUserPath, Integer.toString(userId));
667 userInfo.serialNumber = mNextSerialNumber++;
Amith Yamasani920ace02012-09-20 22:15:37 -0700668 long now = System.currentTimeMillis();
669 userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700670 userInfo.partial = true;
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700671 mUsers.put(userId, userInfo);
672 writeUserListLocked();
673 writeUserLocked(userInfo);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700674 mPm.createNewUserLILPw(userId, userPath);
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700675 userInfo.partial = false;
676 writeUserLocked(userInfo);
677 updateUserIdsLocked();
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700678 }
Dianne Hackborn4428e172012-08-24 17:43:05 -0700679 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700680 if (userInfo != null) {
681 Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
682 addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id);
683 mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
684 android.Manifest.permission.MANAGE_USERS);
685 }
686 } finally {
687 Binder.restoreCallingIdentity(ident);
Amith Yamasani258848d2012-08-10 17:06:33 -0700688 }
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700689 return userInfo;
690 }
691
Amith Yamasani0b285492011-04-14 17:35:23 -0700692 /**
693 * Removes a user and all data directories created for that user. This method should be called
694 * after the user's processes have been terminated.
695 * @param id the user's id
696 */
Amith Yamasani258848d2012-08-10 17:06:33 -0700697 public boolean removeUser(int userHandle) {
Amith Yamasani2a003292012-08-14 18:25:45 -0700698 checkManageUsersPermission("Only the system can remove users");
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700699 final UserInfo user;
700 synchronized (mPackagesLock) {
701 user = mUsers.get(userHandle);
702 if (userHandle == 0 || user == null) {
703 return false;
704 }
Amith Yamasani920ace02012-09-20 22:15:37 -0700705 mRemovingUserIds.add(userHandle);
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700706 }
707
708 int res;
709 try {
710 res = ActivityManagerNative.getDefault().stopUser(userHandle,
711 new IStopUserCallback.Stub() {
712 @Override
713 public void userStopped(int userId) {
714 finishRemoveUser(userId);
715 }
716 @Override
717 public void userStopAborted(int userId) {
718 }
719 });
720 } catch (RemoteException e) {
721 return false;
722 }
723
724 return res == ActivityManager.USER_OP_SUCCESS;
725 }
726
727 void finishRemoveUser(int userHandle) {
Dianne Hackborn4428e172012-08-24 17:43:05 -0700728 synchronized (mInstallLock) {
729 synchronized (mPackagesLock) {
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700730 removeUserStateLocked(userHandle);
Dianne Hackborn4428e172012-08-24 17:43:05 -0700731 }
732 }
Amith Yamasani0cd867c2012-08-22 16:45:47 -0700733
Amith Yamasani2a003292012-08-14 18:25:45 -0700734 // Let other services shutdown any activity
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700735 long ident = Binder.clearCallingIdentity();
736 try {
737 Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
738 addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
739 mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
740 android.Manifest.permission.MANAGE_USERS);
741 } finally {
742 Binder.restoreCallingIdentity(ident);
743 }
Amith Yamasani2a003292012-08-14 18:25:45 -0700744 }
745
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700746 private void removeUserStateLocked(int userHandle) {
747 // Cleanup package manager settings
748 mPm.cleanUpUserLILPw(userHandle);
749
750 // Remove this user from the list
751 mUsers.remove(userHandle);
752 mRemovingUserIds.remove(userHandle);
753 // Remove user file
754 AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml"));
755 userFile.delete();
756 // Update the user list
757 writeUserListLocked();
758 updateUserIdsLocked();
759 removeDirectoryRecursive(Environment.getUserSystemDirectory(userHandle));
760 }
761
Amith Yamasani61f57372012-08-31 12:12:28 -0700762 private void removeDirectoryRecursive(File parent) {
763 if (parent.isDirectory()) {
764 String[] files = parent.list();
765 for (String filename : files) {
766 File child = new File(parent, filename);
767 removeDirectoryRecursive(child);
768 }
769 }
770 parent.delete();
771 }
772
Amith Yamasani2a003292012-08-14 18:25:45 -0700773 @Override
774 public int getUserSerialNumber(int userHandle) {
Dianne Hackborn4428e172012-08-24 17:43:05 -0700775 synchronized (mPackagesLock) {
Amith Yamasani2a003292012-08-14 18:25:45 -0700776 if (!exists(userHandle)) return -1;
Amith Yamasani195263742012-08-21 15:40:12 -0700777 return getUserInfoLocked(userHandle).serialNumber;
Amith Yamasani2a003292012-08-14 18:25:45 -0700778 }
779 }
780
781 @Override
782 public int getUserHandle(int userSerialNumber) {
Dianne Hackborn4428e172012-08-24 17:43:05 -0700783 synchronized (mPackagesLock) {
Amith Yamasani2a003292012-08-14 18:25:45 -0700784 for (int userId : mUserIds) {
Amith Yamasani195263742012-08-21 15:40:12 -0700785 if (getUserInfoLocked(userId).serialNumber == userSerialNumber) return userId;
Amith Yamasani2a003292012-08-14 18:25:45 -0700786 }
787 // Not found
788 return -1;
Amith Yamasani13593602012-03-22 16:16:17 -0700789 }
790 }
791
Amith Yamasani0b285492011-04-14 17:35:23 -0700792 /**
793 * Caches the list of user ids in an array, adjusting the array size when necessary.
794 */
Amith Yamasani13593602012-03-22 16:16:17 -0700795 private void updateUserIdsLocked() {
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700796 int num = 0;
Amith Yamasani0b285492011-04-14 17:35:23 -0700797 for (int i = 0; i < mUsers.size(); i++) {
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700798 if (!mUsers.valueAt(i).partial) {
799 num++;
800 }
801 }
802 int[] newUsers = new int[num];
803 for (int i = 0; i < mUsers.size(); i++) {
804 if (!mUsers.valueAt(i).partial) {
805 newUsers[i] = mUsers.keyAt(i);
806 }
Amith Yamasani0b285492011-04-14 17:35:23 -0700807 }
Dianne Hackborn7767eac2012-08-23 18:25:40 -0700808 mUserIds = newUsers;
Amith Yamasani0b285492011-04-14 17:35:23 -0700809 }
810
811 /**
Amith Yamasani920ace02012-09-20 22:15:37 -0700812 * Make a note of the last started time of a user.
813 * @param userId the user that was just foregrounded
814 */
815 public void userForeground(int userId) {
816 synchronized (mPackagesLock) {
817 UserInfo user = mUsers.get(userId);
818 long now = System.currentTimeMillis();
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700819 if (user == null || user.partial) {
820 Slog.w(LOG_TAG, "userForeground: unknown user #" + userId);
821 return;
822 }
823 if (now > EPOCH_PLUS_30_YEARS) {
Amith Yamasani920ace02012-09-20 22:15:37 -0700824 user.lastLoggedInTime = now;
825 writeUserLocked(user);
826 }
827 }
828 }
829
830 /**
Amith Yamasani0b285492011-04-14 17:35:23 -0700831 * Returns the next available user id, filling in any holes in the ids.
Amith Yamasani742a6712011-05-04 14:49:28 -0700832 * TODO: May not be a good idea to recycle ids, in case it results in confusion
833 * for data and battery stats collection, or unexpected cross-talk.
Amith Yamasani0b285492011-04-14 17:35:23 -0700834 * @return
835 */
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700836 private int getNextAvailableIdLocked() {
Dianne Hackborn4428e172012-08-24 17:43:05 -0700837 synchronized (mPackagesLock) {
Amith Yamasani634cf312012-10-04 17:34:21 -0700838 int i = MIN_USER_ID;
Amith Yamasani195263742012-08-21 15:40:12 -0700839 while (i < Integer.MAX_VALUE) {
Amith Yamasani920ace02012-09-20 22:15:37 -0700840 if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.contains(i)) {
Amith Yamasani195263742012-08-21 15:40:12 -0700841 break;
842 }
843 i++;
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700844 }
Amith Yamasani195263742012-08-21 15:40:12 -0700845 return i;
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700846 }
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700847 }
Amith Yamasani920ace02012-09-20 22:15:37 -0700848
849 @Override
850 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
851 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
852 != PackageManager.PERMISSION_GRANTED) {
853 pw.println("Permission Denial: can't dump UserManager from from pid="
854 + Binder.getCallingPid()
855 + ", uid=" + Binder.getCallingUid()
856 + " without permission "
857 + android.Manifest.permission.DUMP);
858 return;
859 }
860
861 long now = System.currentTimeMillis();
862 StringBuilder sb = new StringBuilder();
863 synchronized (mPackagesLock) {
864 pw.println("Users:");
865 for (int i = 0; i < mUsers.size(); i++) {
866 UserInfo user = mUsers.valueAt(i);
867 if (user == null) continue;
Amith Yamasani634cf312012-10-04 17:34:21 -0700868 pw.print(" "); pw.print(user); pw.print(" serialNo="); pw.print(user.serialNumber);
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -0700869 if (mRemovingUserIds.contains(mUsers.keyAt(i))) pw.print(" <removing> ");
870 if (user.partial) pw.print(" <partial>");
871 pw.println();
Amith Yamasani920ace02012-09-20 22:15:37 -0700872 pw.print(" Created: ");
873 if (user.creationTime == 0) {
874 pw.println("<unknown>");
875 } else {
876 sb.setLength(0);
877 TimeUtils.formatDuration(now - user.creationTime, sb);
878 sb.append(" ago");
879 pw.println(sb);
880 }
881 pw.print(" Last logged in: ");
882 if (user.lastLoggedInTime == 0) {
883 pw.println("<unknown>");
884 } else {
885 sb.setLength(0);
886 TimeUtils.formatDuration(now - user.lastLoggedInTime, sb);
887 sb.append(" ago");
888 pw.println(sb);
889 }
890 }
891 }
892 }
Amith Yamasani4b2e9342011-03-31 12:38:53 -0700893}