UserManagerService.java revision be46532c9fbebf3ab6498c1b78013a33f620cd31
1/* 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 19import static android.text.format.DateUtils.MINUTE_IN_MILLIS; 20 21import android.app.Activity; 22import android.app.ActivityManager; 23import android.app.ActivityManagerNative; 24import android.app.ActivityThread; 25import android.app.IStopUserCallback; 26import android.app.admin.DevicePolicyManager; 27import android.content.BroadcastReceiver; 28import android.content.Context; 29import android.content.Intent; 30import android.content.pm.ApplicationInfo; 31import android.content.pm.PackageManager; 32import android.content.pm.PackageManager.NameNotFoundException; 33import android.content.pm.UserInfo; 34import android.graphics.Bitmap; 35import android.graphics.BitmapFactory; 36import android.os.Binder; 37import android.os.Bundle; 38import android.os.Environment; 39import android.os.FileUtils; 40import android.os.Handler; 41import android.os.IUserManager; 42import android.os.Process; 43import android.os.RemoteException; 44import android.os.UserHandle; 45import android.os.UserManager; 46import android.util.AtomicFile; 47import android.util.Log; 48import android.util.Slog; 49import android.util.SparseArray; 50import android.util.SparseBooleanArray; 51import android.util.TimeUtils; 52import android.util.Xml; 53 54import com.android.internal.content.PackageMonitor; 55import com.android.internal.util.ArrayUtils; 56import com.android.internal.util.FastXmlSerializer; 57 58import org.xmlpull.v1.XmlPullParser; 59import org.xmlpull.v1.XmlPullParserException; 60import org.xmlpull.v1.XmlSerializer; 61 62import java.io.BufferedOutputStream; 63import java.io.File; 64import java.io.FileDescriptor; 65import java.io.FileInputStream; 66import java.io.FileNotFoundException; 67import java.io.FileOutputStream; 68import java.io.IOException; 69import java.io.PrintWriter; 70import java.security.MessageDigest; 71import java.security.NoSuchAlgorithmException; 72import java.security.SecureRandom; 73import java.util.ArrayList; 74import java.util.List; 75 76public class UserManagerService extends IUserManager.Stub { 77 78 private static final String LOG_TAG = "UserManagerService"; 79 80 private static final boolean DBG = false; 81 82 private static final String TAG_NAME = "name"; 83 private static final String ATTR_FLAGS = "flags"; 84 private static final String ATTR_ICON_PATH = "icon"; 85 private static final String ATTR_ID = "id"; 86 private static final String ATTR_CREATION_TIME = "created"; 87 private static final String ATTR_LAST_LOGGED_IN_TIME = "lastLoggedIn"; 88 private static final String ATTR_SALT = "salt"; 89 private static final String ATTR_PIN_HASH = "pinHash"; 90 private static final String ATTR_FAILED_ATTEMPTS = "failedAttempts"; 91 private static final String ATTR_LAST_RETRY_MS = "lastAttemptMs"; 92 private static final String ATTR_SERIAL_NO = "serialNumber"; 93 private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber"; 94 private static final String ATTR_PARTIAL = "partial"; 95 private static final String ATTR_USER_VERSION = "version"; 96 private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId"; 97 private static final String TAG_USERS = "users"; 98 private static final String TAG_USER = "user"; 99 private static final String TAG_RESTRICTIONS = "restrictions"; 100 private static final String TAG_ENTRY = "entry"; 101 private static final String TAG_VALUE = "value"; 102 private static final String ATTR_KEY = "key"; 103 private static final String ATTR_VALUE_TYPE = "type"; 104 private static final String ATTR_MULTIPLE = "m"; 105 106 private static final String ATTR_TYPE_STRING_ARRAY = "sa"; 107 private static final String ATTR_TYPE_STRING = "s"; 108 private static final String ATTR_TYPE_BOOLEAN = "b"; 109 110 private static final String USER_INFO_DIR = "system" + File.separator + "users"; 111 private static final String USER_LIST_FILENAME = "userlist.xml"; 112 private static final String USER_PHOTO_FILENAME = "photo.png"; 113 114 private static final String RESTRICTIONS_FILE_PREFIX = "res_"; 115 private static final String XML_SUFFIX = ".xml"; 116 117 private static final int MIN_USER_ID = 10; 118 119 private static final int USER_VERSION = 4; 120 121 private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms 122 123 // Number of attempts before jumping to the next BACKOFF_TIMES slot 124 private static final int BACKOFF_INC_INTERVAL = 5; 125 126 // Amount of time to force the user to wait before entering the PIN again, after failing 127 // BACKOFF_INC_INTERVAL times. 128 private static final int[] BACKOFF_TIMES = { 0, 30*1000, 60*1000, 5*60*1000, 30*60*1000 }; 129 130 private final Context mContext; 131 private final PackageManagerService mPm; 132 private final Object mInstallLock; 133 private final Object mPackagesLock; 134 135 private final Handler mHandler; 136 137 private final File mUsersDir; 138 private final File mUserListFile; 139 private final File mBaseUserPath; 140 141 private final SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>(); 142 private final SparseArray<Bundle> mUserRestrictions = new SparseArray<Bundle>(); 143 144 class RestrictionsPinState { 145 long salt; 146 String pinHash; 147 int failedAttempts; 148 long lastAttemptTime; 149 } 150 151 private final SparseArray<RestrictionsPinState> mRestrictionsPinStates = 152 new SparseArray<RestrictionsPinState>(); 153 154 /** 155 * Set of user IDs being actively removed. Removed IDs linger in this set 156 * for several seconds to work around a VFS caching issue. 157 */ 158 // @GuardedBy("mPackagesLock") 159 private final SparseBooleanArray mRemovingUserIds = new SparseBooleanArray(); 160 161 private int[] mUserIds; 162 private boolean mGuestEnabled; 163 private int mNextSerialNumber; 164 private int mUserVersion = 0; 165 166 private static UserManagerService sInstance; 167 168 public static UserManagerService getInstance() { 169 synchronized (UserManagerService.class) { 170 return sInstance; 171 } 172 } 173 174 /** 175 * Available for testing purposes. 176 */ 177 UserManagerService(File dataDir, File baseUserPath) { 178 this(null, null, new Object(), new Object(), dataDir, baseUserPath); 179 } 180 181 /** 182 * Called by package manager to create the service. This is closely 183 * associated with the package manager, and the given lock is the 184 * package manager's own lock. 185 */ 186 UserManagerService(Context context, PackageManagerService pm, 187 Object installLock, Object packagesLock) { 188 this(context, pm, installLock, packagesLock, 189 Environment.getDataDirectory(), 190 new File(Environment.getDataDirectory(), "user")); 191 } 192 193 /** 194 * Available for testing purposes. 195 */ 196 private UserManagerService(Context context, PackageManagerService pm, 197 Object installLock, Object packagesLock, 198 File dataDir, File baseUserPath) { 199 mContext = context; 200 mPm = pm; 201 mInstallLock = installLock; 202 mPackagesLock = packagesLock; 203 mHandler = new Handler(); 204 synchronized (mInstallLock) { 205 synchronized (mPackagesLock) { 206 mUsersDir = new File(dataDir, USER_INFO_DIR); 207 mUsersDir.mkdirs(); 208 // Make zeroth user directory, for services to migrate their files to that location 209 File userZeroDir = new File(mUsersDir, "0"); 210 userZeroDir.mkdirs(); 211 mBaseUserPath = baseUserPath; 212 FileUtils.setPermissions(mUsersDir.toString(), 213 FileUtils.S_IRWXU|FileUtils.S_IRWXG 214 |FileUtils.S_IROTH|FileUtils.S_IXOTH, 215 -1, -1); 216 mUserListFile = new File(mUsersDir, USER_LIST_FILENAME); 217 readUserListLocked(); 218 // Prune out any partially created/partially removed users. 219 ArrayList<UserInfo> partials = new ArrayList<UserInfo>(); 220 for (int i = 0; i < mUsers.size(); i++) { 221 UserInfo ui = mUsers.valueAt(i); 222 if (ui.partial && i != 0) { 223 partials.add(ui); 224 } 225 } 226 for (int i = 0; i < partials.size(); i++) { 227 UserInfo ui = partials.get(i); 228 Slog.w(LOG_TAG, "Removing partially created user #" + i 229 + " (name=" + ui.name + ")"); 230 removeUserStateLocked(ui.id); 231 } 232 sInstance = this; 233 } 234 } 235 } 236 237 void systemReady() { 238 mUserPackageMonitor.register(mContext, null, UserHandle.ALL, false); 239 userForeground(UserHandle.USER_OWNER); 240 } 241 242 @Override 243 public List<UserInfo> getUsers(boolean excludeDying) { 244 checkManageUsersPermission("query users"); 245 synchronized (mPackagesLock) { 246 ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size()); 247 for (int i = 0; i < mUsers.size(); i++) { 248 UserInfo ui = mUsers.valueAt(i); 249 if (ui.partial) { 250 continue; 251 } 252 if (!excludeDying || !mRemovingUserIds.get(ui.id)) { 253 users.add(ui); 254 } 255 } 256 return users; 257 } 258 } 259 260 @Override 261 public List<UserInfo> getProfiles(int userId, boolean enabledOnly) { 262 if (userId != UserHandle.getCallingUserId()) { 263 checkManageUsersPermission("getting profiles related to user " + userId); 264 } 265 final long ident = Binder.clearCallingIdentity(); 266 try { 267 synchronized (mPackagesLock) { 268 return getProfilesLocked(userId, enabledOnly); 269 } 270 } finally { 271 Binder.restoreCallingIdentity(ident); 272 } 273 } 274 275 /** Assume permissions already checked and caller's identity cleared */ 276 private List<UserInfo> getProfilesLocked(int userId, boolean enabledOnly) { 277 // Getting the service here is not good for testing purposes. 278 // However, this service is not available when UserManagerService starts 279 // up so we need a lazy load. 280 281 DevicePolicyManager dpm = null; 282 if (enabledOnly) { 283 dpm = (DevicePolicyManager) 284 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 285 } 286 287 UserInfo user = getUserInfoLocked(userId); 288 ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size()); 289 for (int i = 0; i < mUsers.size(); i++) { 290 UserInfo profile = mUsers.valueAt(i); 291 if (!isProfileOf(user, profile)) { 292 continue; 293 } 294 295 if (enabledOnly && profile.isManagedProfile()) { 296 if (dpm != null) { 297 if (!dpm.isProfileEnabled(profile.id)) { 298 continue; 299 } 300 } else { 301 Log.w(LOG_TAG, 302 "Attempting to reach DevicePolicyManager before it is started"); 303 // TODO: There might be system apps that need to call this. 304 // Make sure that DevicePolicyManagerService is ready at that 305 // time (otherwise, any default value is a bad one). 306 throw new IllegalArgumentException(String.format( 307 "Attempting to get enabled profiles for %d before " 308 + "DevicePolicyManagerService has been started.", 309 userId)); 310 } 311 } 312 users.add(profile); 313 } 314 return users; 315 } 316 317 private boolean isProfileOf(UserInfo user, UserInfo profile) { 318 return user.id == profile.id || 319 (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID 320 && user.profileGroupId == profile.profileGroupId); 321 } 322 323 @Override 324 public UserInfo getUserInfo(int userId) { 325 checkManageUsersPermission("query user"); 326 synchronized (mPackagesLock) { 327 return getUserInfoLocked(userId); 328 } 329 } 330 331 @Override 332 public boolean isRestricted() { 333 synchronized (mPackagesLock) { 334 return getUserInfoLocked(UserHandle.getCallingUserId()).isRestricted(); 335 } 336 } 337 338 /* 339 * Should be locked on mUsers before calling this. 340 */ 341 private UserInfo getUserInfoLocked(int userId) { 342 UserInfo ui = mUsers.get(userId); 343 // If it is partial and not in the process of being removed, return as unknown user. 344 if (ui != null && ui.partial && !mRemovingUserIds.get(userId)) { 345 Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId); 346 return null; 347 } 348 return ui; 349 } 350 351 public boolean exists(int userId) { 352 synchronized (mPackagesLock) { 353 return ArrayUtils.contains(mUserIds, userId); 354 } 355 } 356 357 @Override 358 public void setUserName(int userId, String name) { 359 checkManageUsersPermission("rename users"); 360 boolean changed = false; 361 synchronized (mPackagesLock) { 362 UserInfo info = mUsers.get(userId); 363 if (info == null || info.partial) { 364 Slog.w(LOG_TAG, "setUserName: unknown user #" + userId); 365 return; 366 } 367 if (name != null && !name.equals(info.name)) { 368 info.name = name; 369 writeUserLocked(info); 370 changed = true; 371 } 372 } 373 if (changed) { 374 sendUserInfoChangedBroadcast(userId); 375 } 376 } 377 378 @Override 379 public void setUserIcon(int userId, Bitmap bitmap) { 380 checkManageUsersPermission("update users"); 381 synchronized (mPackagesLock) { 382 UserInfo info = mUsers.get(userId); 383 if (info == null || info.partial) { 384 Slog.w(LOG_TAG, "setUserIcon: unknown user #" + userId); 385 return; 386 } 387 writeBitmapLocked(info, bitmap); 388 writeUserLocked(info); 389 } 390 sendUserInfoChangedBroadcast(userId); 391 } 392 393 private void sendUserInfoChangedBroadcast(int userId) { 394 Intent changedIntent = new Intent(Intent.ACTION_USER_INFO_CHANGED); 395 changedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); 396 changedIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 397 mContext.sendBroadcastAsUser(changedIntent, UserHandle.ALL); 398 } 399 400 @Override 401 public Bitmap getUserIcon(int userId) { 402 checkManageUsersPermission("read users"); 403 synchronized (mPackagesLock) { 404 UserInfo info = mUsers.get(userId); 405 if (info == null || info.partial) { 406 Slog.w(LOG_TAG, "getUserIcon: unknown user #" + userId); 407 return null; 408 } 409 if (info.iconPath == null) { 410 return null; 411 } 412 return BitmapFactory.decodeFile(info.iconPath); 413 } 414 } 415 416 @Override 417 public void setGuestEnabled(boolean enable) { 418 checkManageUsersPermission("enable guest users"); 419 synchronized (mPackagesLock) { 420 if (mGuestEnabled != enable) { 421 mGuestEnabled = enable; 422 // Erase any guest user that currently exists 423 for (int i = 0; i < mUsers.size(); i++) { 424 UserInfo user = mUsers.valueAt(i); 425 if (!user.partial && user.isGuest()) { 426 if (!enable) { 427 removeUser(user.id); 428 } 429 return; 430 } 431 } 432 // No guest was found 433 if (enable) { 434 createUser("Guest", UserInfo.FLAG_GUEST); 435 } 436 } 437 } 438 } 439 440 @Override 441 public boolean isGuestEnabled() { 442 synchronized (mPackagesLock) { 443 return mGuestEnabled; 444 } 445 } 446 447 @Override 448 public void wipeUser(int userHandle) { 449 checkManageUsersPermission("wipe user"); 450 // TODO: 451 } 452 453 public void makeInitialized(int userId) { 454 checkManageUsersPermission("makeInitialized"); 455 synchronized (mPackagesLock) { 456 UserInfo info = mUsers.get(userId); 457 if (info == null || info.partial) { 458 Slog.w(LOG_TAG, "makeInitialized: unknown user #" + userId); 459 } 460 if ((info.flags&UserInfo.FLAG_INITIALIZED) == 0) { 461 info.flags |= UserInfo.FLAG_INITIALIZED; 462 writeUserLocked(info); 463 } 464 } 465 } 466 467 @Override 468 public Bundle getUserRestrictions(int userId) { 469 // checkManageUsersPermission("getUserRestrictions"); 470 471 synchronized (mPackagesLock) { 472 Bundle restrictions = mUserRestrictions.get(userId); 473 return restrictions != null ? new Bundle(restrictions) : new Bundle(); 474 } 475 } 476 477 @Override 478 public void setUserRestrictions(Bundle restrictions, int userId) { 479 checkManageUsersPermission("setUserRestrictions"); 480 if (restrictions == null) return; 481 482 synchronized (mPackagesLock) { 483 mUserRestrictions.get(userId).clear(); 484 mUserRestrictions.get(userId).putAll(restrictions); 485 writeUserLocked(mUsers.get(userId)); 486 } 487 } 488 489 /** 490 * Check if we've hit the limit of how many users can be created. 491 */ 492 private boolean isUserLimitReachedLocked() { 493 int nUsers = mUsers.size(); 494 return nUsers >= UserManager.getMaxSupportedUsers(); 495 } 496 497 /** 498 * Enforces that only the system UID or root's UID or apps that have the 499 * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} 500 * permission can make certain calls to the UserManager. 501 * 502 * @param message used as message if SecurityException is thrown 503 * @throws SecurityException if the caller is not system or root 504 */ 505 private static final void checkManageUsersPermission(String message) { 506 final int uid = Binder.getCallingUid(); 507 if (uid != Process.SYSTEM_UID && uid != 0 508 && ActivityManager.checkComponentPermission( 509 android.Manifest.permission.MANAGE_USERS, 510 uid, -1, true) != PackageManager.PERMISSION_GRANTED) { 511 throw new SecurityException("You need MANAGE_USERS permission to: " + message); 512 } 513 } 514 515 private void writeBitmapLocked(UserInfo info, Bitmap bitmap) { 516 try { 517 File dir = new File(mUsersDir, Integer.toString(info.id)); 518 File file = new File(dir, USER_PHOTO_FILENAME); 519 if (!dir.exists()) { 520 dir.mkdir(); 521 FileUtils.setPermissions( 522 dir.getPath(), 523 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, 524 -1, -1); 525 } 526 FileOutputStream os; 527 if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, os = new FileOutputStream(file))) { 528 info.iconPath = file.getAbsolutePath(); 529 } 530 try { 531 os.close(); 532 } catch (IOException ioe) { 533 // What the ... ! 534 } 535 } catch (FileNotFoundException e) { 536 Slog.w(LOG_TAG, "Error setting photo for user ", e); 537 } 538 } 539 540 /** 541 * Returns an array of user ids. This array is cached here for quick access, so do not modify or 542 * cache it elsewhere. 543 * @return the array of user ids. 544 */ 545 public int[] getUserIds() { 546 synchronized (mPackagesLock) { 547 return mUserIds; 548 } 549 } 550 551 int[] getUserIdsLPr() { 552 return mUserIds; 553 } 554 555 private void readUserListLocked() { 556 mGuestEnabled = false; 557 if (!mUserListFile.exists()) { 558 fallbackToSingleUserLocked(); 559 return; 560 } 561 FileInputStream fis = null; 562 AtomicFile userListFile = new AtomicFile(mUserListFile); 563 try { 564 fis = userListFile.openRead(); 565 XmlPullParser parser = Xml.newPullParser(); 566 parser.setInput(fis, null); 567 int type; 568 while ((type = parser.next()) != XmlPullParser.START_TAG 569 && type != XmlPullParser.END_DOCUMENT) { 570 ; 571 } 572 573 if (type != XmlPullParser.START_TAG) { 574 Slog.e(LOG_TAG, "Unable to read user list"); 575 fallbackToSingleUserLocked(); 576 return; 577 } 578 579 mNextSerialNumber = -1; 580 if (parser.getName().equals(TAG_USERS)) { 581 String lastSerialNumber = parser.getAttributeValue(null, ATTR_NEXT_SERIAL_NO); 582 if (lastSerialNumber != null) { 583 mNextSerialNumber = Integer.parseInt(lastSerialNumber); 584 } 585 String versionNumber = parser.getAttributeValue(null, ATTR_USER_VERSION); 586 if (versionNumber != null) { 587 mUserVersion = Integer.parseInt(versionNumber); 588 } 589 } 590 591 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { 592 if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) { 593 String id = parser.getAttributeValue(null, ATTR_ID); 594 UserInfo user = readUserLocked(Integer.parseInt(id)); 595 596 if (user != null) { 597 mUsers.put(user.id, user); 598 if (user.isGuest()) { 599 mGuestEnabled = true; 600 } 601 if (mNextSerialNumber < 0 || mNextSerialNumber <= user.id) { 602 mNextSerialNumber = user.id + 1; 603 } 604 } 605 } 606 } 607 updateUserIdsLocked(); 608 upgradeIfNecessaryLocked(); 609 } catch (IOException ioe) { 610 fallbackToSingleUserLocked(); 611 } catch (XmlPullParserException pe) { 612 fallbackToSingleUserLocked(); 613 } finally { 614 if (fis != null) { 615 try { 616 fis.close(); 617 } catch (IOException e) { 618 } 619 } 620 } 621 } 622 623 /** 624 * Upgrade steps between versions, either for fixing bugs or changing the data format. 625 */ 626 private void upgradeIfNecessaryLocked() { 627 int userVersion = mUserVersion; 628 if (userVersion < 1) { 629 // Assign a proper name for the owner, if not initialized correctly before 630 UserInfo user = mUsers.get(UserHandle.USER_OWNER); 631 if ("Primary".equals(user.name)) { 632 user.name = mContext.getResources().getString(com.android.internal.R.string.owner_name); 633 writeUserLocked(user); 634 } 635 userVersion = 1; 636 } 637 638 if (userVersion < 2) { 639 // Owner should be marked as initialized 640 UserInfo user = mUsers.get(UserHandle.USER_OWNER); 641 if ((user.flags & UserInfo.FLAG_INITIALIZED) == 0) { 642 user.flags |= UserInfo.FLAG_INITIALIZED; 643 writeUserLocked(user); 644 } 645 userVersion = 2; 646 } 647 648 649 if (userVersion < 4) { 650 userVersion = 4; 651 } 652 653 if (userVersion < USER_VERSION) { 654 Slog.w(LOG_TAG, "User version " + mUserVersion + " didn't upgrade as expected to " 655 + USER_VERSION); 656 } else { 657 mUserVersion = userVersion; 658 writeUserListLocked(); 659 } 660 } 661 662 private void fallbackToSingleUserLocked() { 663 // Create the primary user 664 UserInfo primary = new UserInfo(UserHandle.USER_OWNER, 665 mContext.getResources().getString(com.android.internal.R.string.owner_name), null, 666 UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED); 667 mUsers.put(0, primary); 668 mNextSerialNumber = MIN_USER_ID; 669 mUserVersion = USER_VERSION; 670 671 Bundle restrictions = new Bundle(); 672 mUserRestrictions.append(UserHandle.USER_OWNER, restrictions); 673 674 updateUserIdsLocked(); 675 676 writeUserListLocked(); 677 writeUserLocked(primary); 678 } 679 680 /* 681 * Writes the user file in this format: 682 * 683 * <user flags="20039023" id="0"> 684 * <name>Primary</name> 685 * </user> 686 */ 687 private void writeUserLocked(UserInfo userInfo) { 688 FileOutputStream fos = null; 689 AtomicFile userFile = new AtomicFile(new File(mUsersDir, userInfo.id + XML_SUFFIX)); 690 try { 691 fos = userFile.startWrite(); 692 final BufferedOutputStream bos = new BufferedOutputStream(fos); 693 694 // XmlSerializer serializer = XmlUtils.serializerInstance(); 695 final XmlSerializer serializer = new FastXmlSerializer(); 696 serializer.setOutput(bos, "utf-8"); 697 serializer.startDocument(null, true); 698 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 699 700 serializer.startTag(null, TAG_USER); 701 serializer.attribute(null, ATTR_ID, Integer.toString(userInfo.id)); 702 serializer.attribute(null, ATTR_SERIAL_NO, Integer.toString(userInfo.serialNumber)); 703 serializer.attribute(null, ATTR_FLAGS, Integer.toString(userInfo.flags)); 704 serializer.attribute(null, ATTR_CREATION_TIME, Long.toString(userInfo.creationTime)); 705 serializer.attribute(null, ATTR_LAST_LOGGED_IN_TIME, 706 Long.toString(userInfo.lastLoggedInTime)); 707 RestrictionsPinState pinState = mRestrictionsPinStates.get(userInfo.id); 708 if (pinState != null) { 709 if (pinState.salt != 0) { 710 serializer.attribute(null, ATTR_SALT, Long.toString(pinState.salt)); 711 } 712 if (pinState.pinHash != null) { 713 serializer.attribute(null, ATTR_PIN_HASH, pinState.pinHash); 714 } 715 if (pinState.failedAttempts != 0) { 716 serializer.attribute(null, ATTR_FAILED_ATTEMPTS, 717 Integer.toString(pinState.failedAttempts)); 718 serializer.attribute(null, ATTR_LAST_RETRY_MS, 719 Long.toString(pinState.lastAttemptTime)); 720 } 721 } 722 if (userInfo.iconPath != null) { 723 serializer.attribute(null, ATTR_ICON_PATH, userInfo.iconPath); 724 } 725 if (userInfo.partial) { 726 serializer.attribute(null, ATTR_PARTIAL, "true"); 727 } 728 if (userInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) { 729 serializer.attribute(null, ATTR_PROFILE_GROUP_ID, 730 Integer.toString(userInfo.profileGroupId)); 731 } 732 733 serializer.startTag(null, TAG_NAME); 734 serializer.text(userInfo.name); 735 serializer.endTag(null, TAG_NAME); 736 737 Bundle restrictions = mUserRestrictions.get(userInfo.id); 738 if (restrictions != null) { 739 serializer.startTag(null, TAG_RESTRICTIONS); 740 writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_WIFI); 741 writeBoolean(serializer, restrictions, UserManager.DISALLOW_MODIFY_ACCOUNTS); 742 writeBoolean(serializer, restrictions, UserManager.DISALLOW_INSTALL_APPS); 743 writeBoolean(serializer, restrictions, UserManager.DISALLOW_UNINSTALL_APPS); 744 writeBoolean(serializer, restrictions, UserManager.DISALLOW_SHARE_LOCATION); 745 writeBoolean(serializer, restrictions, 746 UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); 747 writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_BLUETOOTH); 748 writeBoolean(serializer, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER); 749 writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS); 750 writeBoolean(serializer, restrictions, UserManager.DISALLOW_REMOVE_USER); 751 serializer.endTag(null, TAG_RESTRICTIONS); 752 } 753 serializer.endTag(null, TAG_USER); 754 755 serializer.endDocument(); 756 userFile.finishWrite(fos); 757 } catch (Exception ioe) { 758 Slog.e(LOG_TAG, "Error writing user info " + userInfo.id + "\n" + ioe); 759 userFile.failWrite(fos); 760 } 761 } 762 763 /* 764 * Writes the user list file in this format: 765 * 766 * <users nextSerialNumber="3"> 767 * <user id="0"></user> 768 * <user id="2"></user> 769 * </users> 770 */ 771 private void writeUserListLocked() { 772 FileOutputStream fos = null; 773 AtomicFile userListFile = new AtomicFile(mUserListFile); 774 try { 775 fos = userListFile.startWrite(); 776 final BufferedOutputStream bos = new BufferedOutputStream(fos); 777 778 // XmlSerializer serializer = XmlUtils.serializerInstance(); 779 final XmlSerializer serializer = new FastXmlSerializer(); 780 serializer.setOutput(bos, "utf-8"); 781 serializer.startDocument(null, true); 782 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 783 784 serializer.startTag(null, TAG_USERS); 785 serializer.attribute(null, ATTR_NEXT_SERIAL_NO, Integer.toString(mNextSerialNumber)); 786 serializer.attribute(null, ATTR_USER_VERSION, Integer.toString(mUserVersion)); 787 788 for (int i = 0; i < mUsers.size(); i++) { 789 UserInfo user = mUsers.valueAt(i); 790 serializer.startTag(null, TAG_USER); 791 serializer.attribute(null, ATTR_ID, Integer.toString(user.id)); 792 serializer.endTag(null, TAG_USER); 793 } 794 795 serializer.endTag(null, TAG_USERS); 796 797 serializer.endDocument(); 798 userListFile.finishWrite(fos); 799 } catch (Exception e) { 800 userListFile.failWrite(fos); 801 Slog.e(LOG_TAG, "Error writing user list"); 802 } 803 } 804 805 private UserInfo readUserLocked(int id) { 806 int flags = 0; 807 int serialNumber = id; 808 String name = null; 809 String iconPath = null; 810 long creationTime = 0L; 811 long lastLoggedInTime = 0L; 812 long salt = 0L; 813 String pinHash = null; 814 int failedAttempts = 0; 815 int profileGroupId = UserInfo.NO_PROFILE_GROUP_ID; 816 long lastAttemptTime = 0L; 817 boolean partial = false; 818 Bundle restrictions = new Bundle(); 819 820 FileInputStream fis = null; 821 try { 822 AtomicFile userFile = 823 new AtomicFile(new File(mUsersDir, Integer.toString(id) + XML_SUFFIX)); 824 fis = userFile.openRead(); 825 XmlPullParser parser = Xml.newPullParser(); 826 parser.setInput(fis, null); 827 int type; 828 while ((type = parser.next()) != XmlPullParser.START_TAG 829 && type != XmlPullParser.END_DOCUMENT) { 830 ; 831 } 832 833 if (type != XmlPullParser.START_TAG) { 834 Slog.e(LOG_TAG, "Unable to read user " + id); 835 return null; 836 } 837 838 if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) { 839 int storedId = readIntAttribute(parser, ATTR_ID, -1); 840 if (storedId != id) { 841 Slog.e(LOG_TAG, "User id does not match the file name"); 842 return null; 843 } 844 serialNumber = readIntAttribute(parser, ATTR_SERIAL_NO, id); 845 flags = readIntAttribute(parser, ATTR_FLAGS, 0); 846 iconPath = parser.getAttributeValue(null, ATTR_ICON_PATH); 847 creationTime = readLongAttribute(parser, ATTR_CREATION_TIME, 0); 848 lastLoggedInTime = readLongAttribute(parser, ATTR_LAST_LOGGED_IN_TIME, 0); 849 salt = readLongAttribute(parser, ATTR_SALT, 0L); 850 pinHash = parser.getAttributeValue(null, ATTR_PIN_HASH); 851 failedAttempts = readIntAttribute(parser, ATTR_FAILED_ATTEMPTS, 0); 852 lastAttemptTime = readLongAttribute(parser, ATTR_LAST_RETRY_MS, 0L); 853 profileGroupId = readIntAttribute(parser, ATTR_PROFILE_GROUP_ID, 854 UserInfo.NO_PROFILE_GROUP_ID); 855 if (profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) { 856 // This attribute was added and renamed during development of L. 857 // TODO Remove upgrade path by 1st May 2014 858 profileGroupId = readIntAttribute(parser, "relatedGroupId", 859 UserInfo.NO_PROFILE_GROUP_ID); 860 } 861 String valueString = parser.getAttributeValue(null, ATTR_PARTIAL); 862 if ("true".equals(valueString)) { 863 partial = true; 864 } 865 866 int outerDepth = parser.getDepth(); 867 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 868 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 869 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 870 continue; 871 } 872 String tag = parser.getName(); 873 if (TAG_NAME.equals(tag)) { 874 type = parser.next(); 875 if (type == XmlPullParser.TEXT) { 876 name = parser.getText(); 877 } 878 } else if (TAG_RESTRICTIONS.equals(tag)) { 879 readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_WIFI); 880 readBoolean(parser, restrictions, UserManager.DISALLOW_MODIFY_ACCOUNTS); 881 readBoolean(parser, restrictions, UserManager.DISALLOW_INSTALL_APPS); 882 readBoolean(parser, restrictions, UserManager.DISALLOW_UNINSTALL_APPS); 883 readBoolean(parser, restrictions, UserManager.DISALLOW_SHARE_LOCATION); 884 readBoolean(parser, restrictions, 885 UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); 886 readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_BLUETOOTH); 887 readBoolean(parser, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER); 888 readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS); 889 readBoolean(parser, restrictions, UserManager.DISALLOW_REMOVE_USER); 890 } 891 } 892 } 893 894 UserInfo userInfo = new UserInfo(id, name, iconPath, flags); 895 userInfo.serialNumber = serialNumber; 896 userInfo.creationTime = creationTime; 897 userInfo.lastLoggedInTime = lastLoggedInTime; 898 userInfo.partial = partial; 899 userInfo.profileGroupId = profileGroupId; 900 mUserRestrictions.append(id, restrictions); 901 if (salt != 0L) { 902 RestrictionsPinState pinState = mRestrictionsPinStates.get(id); 903 if (pinState == null) { 904 pinState = new RestrictionsPinState(); 905 mRestrictionsPinStates.put(id, pinState); 906 } 907 pinState.salt = salt; 908 pinState.pinHash = pinHash; 909 pinState.failedAttempts = failedAttempts; 910 pinState.lastAttemptTime = lastAttemptTime; 911 } 912 return userInfo; 913 914 } catch (IOException ioe) { 915 } catch (XmlPullParserException pe) { 916 } finally { 917 if (fis != null) { 918 try { 919 fis.close(); 920 } catch (IOException e) { 921 } 922 } 923 } 924 return null; 925 } 926 927 private void readBoolean(XmlPullParser parser, Bundle restrictions, 928 String restrictionKey) { 929 String value = parser.getAttributeValue(null, restrictionKey); 930 if (value != null) { 931 restrictions.putBoolean(restrictionKey, Boolean.parseBoolean(value)); 932 } 933 } 934 935 private void writeBoolean(XmlSerializer xml, Bundle restrictions, String restrictionKey) 936 throws IOException { 937 if (restrictions.containsKey(restrictionKey)) { 938 xml.attribute(null, restrictionKey, 939 Boolean.toString(restrictions.getBoolean(restrictionKey))); 940 } 941 } 942 943 private int readIntAttribute(XmlPullParser parser, String attr, int defaultValue) { 944 String valueString = parser.getAttributeValue(null, attr); 945 if (valueString == null) return defaultValue; 946 try { 947 return Integer.parseInt(valueString); 948 } catch (NumberFormatException nfe) { 949 return defaultValue; 950 } 951 } 952 953 private long readLongAttribute(XmlPullParser parser, String attr, long defaultValue) { 954 String valueString = parser.getAttributeValue(null, attr); 955 if (valueString == null) return defaultValue; 956 try { 957 return Long.parseLong(valueString); 958 } catch (NumberFormatException nfe) { 959 return defaultValue; 960 } 961 } 962 963 private boolean isPackageInstalled(String pkg, int userId) { 964 final ApplicationInfo info = mPm.getApplicationInfo(pkg, 965 PackageManager.GET_UNINSTALLED_PACKAGES, 966 userId); 967 if (info == null || (info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) { 968 return false; 969 } 970 return true; 971 } 972 973 /** 974 * Removes all the restrictions files (res_<packagename>) for a given user, if all is true, 975 * else removes only those packages that have been uninstalled. 976 * Does not do any permissions checking. 977 */ 978 private void cleanAppRestrictions(int userId, boolean all) { 979 synchronized (mPackagesLock) { 980 File dir = Environment.getUserSystemDirectory(userId); 981 String[] files = dir.list(); 982 if (files == null) return; 983 for (String fileName : files) { 984 if (fileName.startsWith(RESTRICTIONS_FILE_PREFIX)) { 985 File resFile = new File(dir, fileName); 986 if (resFile.exists()) { 987 if (all) { 988 resFile.delete(); 989 } else { 990 String pkg = restrictionsFileNameToPackage(fileName); 991 if (!isPackageInstalled(pkg, userId)) { 992 resFile.delete(); 993 } 994 } 995 } 996 } 997 } 998 } 999 } 1000 1001 /** 1002 * Removes the app restrictions file for a specific package and user id, if it exists. 1003 */ 1004 private void cleanAppRestrictionsForPackage(String pkg, int userId) { 1005 synchronized (mPackagesLock) { 1006 File dir = Environment.getUserSystemDirectory(userId); 1007 File resFile = new File(dir, packageToRestrictionsFileName(pkg)); 1008 if (resFile.exists()) { 1009 resFile.delete(); 1010 } 1011 } 1012 } 1013 1014 private int getNextProfileGroupIdLocked() { 1015 int maxGroupId = UserInfo.NO_PROFILE_GROUP_ID; 1016 for (int i = 0; i < mUsers.size(); i++) { 1017 UserInfo ui = mUsers.valueAt(i); 1018 if (maxGroupId < ui.profileGroupId) { 1019 maxGroupId = ui.profileGroupId; 1020 } 1021 } 1022 return maxGroupId + 1; 1023 } 1024 1025 @Override 1026 public UserInfo createProfileForUser(String name, int flags, int userId) { 1027 checkManageUsersPermission("Only the system can create users"); 1028 if (userId != UserHandle.USER_OWNER) { 1029 Slog.w(LOG_TAG, "Only user owner can have profiles"); 1030 return null; 1031 } 1032 return createUserInternal(name, flags, userId); 1033 } 1034 1035 @Override 1036 public UserInfo createUser(String name, int flags) { 1037 checkManageUsersPermission("Only the system can create users"); 1038 return createUserInternal(name, flags, UserHandle.USER_NULL); 1039 } 1040 1041 private UserInfo createUserInternal(String name, int flags, int profileId) { 1042 final long ident = Binder.clearCallingIdentity(); 1043 UserInfo userInfo = null; 1044 try { 1045 synchronized (mInstallLock) { 1046 synchronized (mPackagesLock) { 1047 UserInfo profile = null; 1048 if (profileId != UserHandle.USER_NULL) { 1049 profile = getUserInfoLocked(profileId); 1050 if (profile == null) return null; 1051 } 1052 if (isUserLimitReachedLocked()) return null; 1053 int userId = getNextAvailableIdLocked(); 1054 userInfo = new UserInfo(userId, name, null, flags); 1055 File userPath = new File(mBaseUserPath, Integer.toString(userId)); 1056 userInfo.serialNumber = mNextSerialNumber++; 1057 long now = System.currentTimeMillis(); 1058 userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0; 1059 userInfo.partial = true; 1060 Environment.getUserSystemDirectory(userInfo.id).mkdirs(); 1061 mUsers.put(userId, userInfo); 1062 writeUserListLocked(); 1063 if (profile != null) { 1064 if (profile.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) { 1065 profile.profileGroupId = getNextProfileGroupIdLocked(); 1066 writeUserLocked(profile); 1067 } 1068 userInfo.profileGroupId = profile.profileGroupId; 1069 } 1070 writeUserLocked(userInfo); 1071 mPm.createNewUserLILPw(userId, userPath); 1072 userInfo.partial = false; 1073 writeUserLocked(userInfo); 1074 updateUserIdsLocked(); 1075 Bundle restrictions = new Bundle(); 1076 mUserRestrictions.append(userId, restrictions); 1077 } 1078 } 1079 if (userInfo != null) { 1080 Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED); 1081 addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id); 1082 mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL, 1083 android.Manifest.permission.MANAGE_USERS); 1084 } 1085 } finally { 1086 Binder.restoreCallingIdentity(ident); 1087 } 1088 return userInfo; 1089 } 1090 1091 /** 1092 * Removes a user and all data directories created for that user. This method should be called 1093 * after the user's processes have been terminated. 1094 * @param userHandle the user's id 1095 */ 1096 public boolean removeUser(int userHandle) { 1097 checkManageUsersPermission("Only the system can remove users"); 1098 final UserInfo user; 1099 synchronized (mPackagesLock) { 1100 user = mUsers.get(userHandle); 1101 if (userHandle == 0 || user == null) { 1102 return false; 1103 } 1104 mRemovingUserIds.put(userHandle, true); 1105 // Set this to a partially created user, so that the user will be purged 1106 // on next startup, in case the runtime stops now before stopping and 1107 // removing the user completely. 1108 user.partial = true; 1109 writeUserLocked(user); 1110 } 1111 if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle); 1112 int res; 1113 try { 1114 res = ActivityManagerNative.getDefault().stopUser(userHandle, 1115 new IStopUserCallback.Stub() { 1116 @Override 1117 public void userStopped(int userId) { 1118 finishRemoveUser(userId); 1119 } 1120 @Override 1121 public void userStopAborted(int userId) { 1122 } 1123 }); 1124 } catch (RemoteException e) { 1125 return false; 1126 } 1127 1128 return res == ActivityManager.USER_OP_SUCCESS; 1129 } 1130 1131 void finishRemoveUser(final int userHandle) { 1132 if (DBG) Slog.i(LOG_TAG, "finishRemoveUser " + userHandle); 1133 // Let other services shutdown any activity and clean up their state before completely 1134 // wiping the user's system directory and removing from the user list 1135 long ident = Binder.clearCallingIdentity(); 1136 try { 1137 Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED); 1138 addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle); 1139 mContext.sendOrderedBroadcastAsUser(addedIntent, UserHandle.ALL, 1140 android.Manifest.permission.MANAGE_USERS, 1141 1142 new BroadcastReceiver() { 1143 @Override 1144 public void onReceive(Context context, Intent intent) { 1145 if (DBG) { 1146 Slog.i(LOG_TAG, 1147 "USER_REMOVED broadcast sent, cleaning up user data " 1148 + userHandle); 1149 } 1150 new Thread() { 1151 public void run() { 1152 synchronized (mInstallLock) { 1153 synchronized (mPackagesLock) { 1154 removeUserStateLocked(userHandle); 1155 } 1156 } 1157 } 1158 }.start(); 1159 } 1160 }, 1161 1162 null, Activity.RESULT_OK, null, null); 1163 } finally { 1164 Binder.restoreCallingIdentity(ident); 1165 } 1166 } 1167 1168 private void removeUserStateLocked(final int userHandle) { 1169 // Cleanup package manager settings 1170 mPm.cleanUpUserLILPw(userHandle); 1171 1172 // Remove this user from the list 1173 mUsers.remove(userHandle); 1174 1175 // Have user ID linger for several seconds to let external storage VFS 1176 // cache entries expire. This must be greater than the 'entry_valid' 1177 // timeout used by the FUSE daemon. 1178 mHandler.postDelayed(new Runnable() { 1179 @Override 1180 public void run() { 1181 synchronized (mPackagesLock) { 1182 mRemovingUserIds.delete(userHandle); 1183 } 1184 } 1185 }, MINUTE_IN_MILLIS); 1186 1187 mRestrictionsPinStates.remove(userHandle); 1188 // Remove user file 1189 AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX)); 1190 userFile.delete(); 1191 // Update the user list 1192 writeUserListLocked(); 1193 updateUserIdsLocked(); 1194 removeDirectoryRecursive(Environment.getUserSystemDirectory(userHandle)); 1195 } 1196 1197 private void removeDirectoryRecursive(File parent) { 1198 if (parent.isDirectory()) { 1199 String[] files = parent.list(); 1200 for (String filename : files) { 1201 File child = new File(parent, filename); 1202 removeDirectoryRecursive(child); 1203 } 1204 } 1205 parent.delete(); 1206 } 1207 1208 @Override 1209 public Bundle getApplicationRestrictions(String packageName) { 1210 return getApplicationRestrictionsForUser(packageName, UserHandle.getCallingUserId()); 1211 } 1212 1213 @Override 1214 public Bundle getApplicationRestrictionsForUser(String packageName, int userId) { 1215 if (UserHandle.getCallingUserId() != userId 1216 || !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) { 1217 checkManageUsersPermission("Only system can get restrictions for other users/apps"); 1218 } 1219 synchronized (mPackagesLock) { 1220 // Read the restrictions from XML 1221 return readApplicationRestrictionsLocked(packageName, userId); 1222 } 1223 } 1224 1225 @Override 1226 public void setApplicationRestrictions(String packageName, Bundle restrictions, 1227 int userId) { 1228 if (UserHandle.getCallingUserId() != userId 1229 || !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) { 1230 checkManageUsersPermission("Only system can set restrictions for other users/apps"); 1231 } 1232 synchronized (mPackagesLock) { 1233 // Write the restrictions to XML 1234 writeApplicationRestrictionsLocked(packageName, restrictions, userId); 1235 } 1236 1237 // Notify package of changes via an intent - only sent to explicitly registered receivers. 1238 Intent changeIntent = new Intent(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED); 1239 changeIntent.setPackage(packageName); 1240 changeIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 1241 mContext.sendBroadcastAsUser(changeIntent, new UserHandle(userId)); 1242 } 1243 1244 @Override 1245 public boolean setRestrictionsChallenge(String newPin) { 1246 checkManageUsersPermission("Only system can modify the restrictions pin"); 1247 int userId = UserHandle.getCallingUserId(); 1248 synchronized (mPackagesLock) { 1249 RestrictionsPinState pinState = mRestrictionsPinStates.get(userId); 1250 if (pinState == null) { 1251 pinState = new RestrictionsPinState(); 1252 } 1253 if (newPin == null) { 1254 pinState.salt = 0; 1255 pinState.pinHash = null; 1256 } else { 1257 try { 1258 pinState.salt = SecureRandom.getInstance("SHA1PRNG").nextLong(); 1259 } catch (NoSuchAlgorithmException e) { 1260 pinState.salt = (long) (Math.random() * Long.MAX_VALUE); 1261 } 1262 pinState.pinHash = passwordToHash(newPin, pinState.salt); 1263 pinState.failedAttempts = 0; 1264 } 1265 mRestrictionsPinStates.put(userId, pinState); 1266 writeUserLocked(mUsers.get(userId)); 1267 } 1268 return true; 1269 } 1270 1271 @Override 1272 public int checkRestrictionsChallenge(String pin) { 1273 checkManageUsersPermission("Only system can verify the restrictions pin"); 1274 int userId = UserHandle.getCallingUserId(); 1275 synchronized (mPackagesLock) { 1276 RestrictionsPinState pinState = mRestrictionsPinStates.get(userId); 1277 // If there's no pin set, return error code 1278 if (pinState == null || pinState.salt == 0 || pinState.pinHash == null) { 1279 return UserManager.PIN_VERIFICATION_FAILED_NOT_SET; 1280 } else if (pin == null) { 1281 // If just checking if user can be prompted, return remaining time 1282 int waitTime = getRemainingTimeForPinAttempt(pinState); 1283 Slog.d(LOG_TAG, "Remaining waittime peek=" + waitTime); 1284 return waitTime; 1285 } else { 1286 int waitTime = getRemainingTimeForPinAttempt(pinState); 1287 Slog.d(LOG_TAG, "Remaining waittime=" + waitTime); 1288 if (waitTime > 0) { 1289 return waitTime; 1290 } 1291 if (passwordToHash(pin, pinState.salt).equals(pinState.pinHash)) { 1292 pinState.failedAttempts = 0; 1293 writeUserLocked(mUsers.get(userId)); 1294 return UserManager.PIN_VERIFICATION_SUCCESS; 1295 } else { 1296 pinState.failedAttempts++; 1297 pinState.lastAttemptTime = System.currentTimeMillis(); 1298 writeUserLocked(mUsers.get(userId)); 1299 return waitTime; 1300 } 1301 } 1302 } 1303 } 1304 1305 private int getRemainingTimeForPinAttempt(RestrictionsPinState pinState) { 1306 int backoffIndex = Math.min(pinState.failedAttempts / BACKOFF_INC_INTERVAL, 1307 BACKOFF_TIMES.length - 1); 1308 int backoffTime = (pinState.failedAttempts % BACKOFF_INC_INTERVAL) == 0 ? 1309 BACKOFF_TIMES[backoffIndex] : 0; 1310 return (int) Math.max(backoffTime + pinState.lastAttemptTime - System.currentTimeMillis(), 1311 0); 1312 } 1313 1314 @Override 1315 public boolean hasRestrictionsChallenge() { 1316 int userId = UserHandle.getCallingUserId(); 1317 synchronized (mPackagesLock) { 1318 return hasRestrictionsPinLocked(userId); 1319 } 1320 } 1321 1322 private boolean hasRestrictionsPinLocked(int userId) { 1323 RestrictionsPinState pinState = mRestrictionsPinStates.get(userId); 1324 if (pinState == null || pinState.salt == 0 || pinState.pinHash == null) { 1325 return false; 1326 } 1327 return true; 1328 } 1329 1330 @Override 1331 public void removeRestrictions() { 1332 checkManageUsersPermission("Only system can remove restrictions"); 1333 final int userHandle = UserHandle.getCallingUserId(); 1334 removeRestrictionsForUser(userHandle, true); 1335 } 1336 1337 private void removeRestrictionsForUser(final int userHandle, boolean unblockApps) { 1338 synchronized (mPackagesLock) { 1339 // Remove all user restrictions 1340 setUserRestrictions(new Bundle(), userHandle); 1341 // Remove restrictions pin 1342 setRestrictionsChallenge(null); 1343 // Remove any app restrictions 1344 cleanAppRestrictions(userHandle, true); 1345 } 1346 if (unblockApps) { 1347 unblockAllAppsForUser(userHandle); 1348 } 1349 } 1350 1351 private void unblockAllAppsForUser(final int userHandle) { 1352 mHandler.post(new Runnable() { 1353 @Override 1354 public void run() { 1355 List<ApplicationInfo> apps = 1356 mPm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES, 1357 userHandle).getList(); 1358 final long ident = Binder.clearCallingIdentity(); 1359 try { 1360 for (ApplicationInfo appInfo : apps) { 1361 if ((appInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0 1362 && (appInfo.flags & ApplicationInfo.FLAG_BLOCKED) != 0) { 1363 mPm.setApplicationBlockedSettingAsUser(appInfo.packageName, false, 1364 userHandle); 1365 } 1366 } 1367 } finally { 1368 Binder.restoreCallingIdentity(ident); 1369 } 1370 } 1371 }); 1372 } 1373 1374 /* 1375 * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash. 1376 * Not the most secure, but it is at least a second level of protection. First level is that 1377 * the file is in a location only readable by the system process. 1378 * @param password the password. 1379 * @param salt the randomly generated salt 1380 * @return the hash of the pattern in a String. 1381 */ 1382 private String passwordToHash(String password, long salt) { 1383 if (password == null) { 1384 return null; 1385 } 1386 String algo = null; 1387 String hashed = salt + password; 1388 try { 1389 byte[] saltedPassword = (password + salt).getBytes(); 1390 byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword); 1391 byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword); 1392 hashed = toHex(sha1) + toHex(md5); 1393 } catch (NoSuchAlgorithmException e) { 1394 Log.w(LOG_TAG, "Failed to encode string because of missing algorithm: " + algo); 1395 } 1396 return hashed; 1397 } 1398 1399 private static String toHex(byte[] ary) { 1400 final String hex = "0123456789ABCDEF"; 1401 String ret = ""; 1402 for (int i = 0; i < ary.length; i++) { 1403 ret += hex.charAt((ary[i] >> 4) & 0xf); 1404 ret += hex.charAt(ary[i] & 0xf); 1405 } 1406 return ret; 1407 } 1408 1409 private int getUidForPackage(String packageName) { 1410 long ident = Binder.clearCallingIdentity(); 1411 try { 1412 return mContext.getPackageManager().getApplicationInfo(packageName, 1413 PackageManager.GET_UNINSTALLED_PACKAGES).uid; 1414 } catch (NameNotFoundException nnfe) { 1415 return -1; 1416 } finally { 1417 Binder.restoreCallingIdentity(ident); 1418 } 1419 } 1420 1421 private Bundle readApplicationRestrictionsLocked(String packageName, 1422 int userId) { 1423 final Bundle restrictions = new Bundle(); 1424 final ArrayList<String> values = new ArrayList<String>(); 1425 1426 FileInputStream fis = null; 1427 try { 1428 AtomicFile restrictionsFile = 1429 new AtomicFile(new File(Environment.getUserSystemDirectory(userId), 1430 packageToRestrictionsFileName(packageName))); 1431 fis = restrictionsFile.openRead(); 1432 XmlPullParser parser = Xml.newPullParser(); 1433 parser.setInput(fis, null); 1434 int type; 1435 while ((type = parser.next()) != XmlPullParser.START_TAG 1436 && type != XmlPullParser.END_DOCUMENT) { 1437 ; 1438 } 1439 1440 if (type != XmlPullParser.START_TAG) { 1441 Slog.e(LOG_TAG, "Unable to read restrictions file " 1442 + restrictionsFile.getBaseFile()); 1443 return restrictions; 1444 } 1445 1446 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { 1447 if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_ENTRY)) { 1448 String key = parser.getAttributeValue(null, ATTR_KEY); 1449 String valType = parser.getAttributeValue(null, ATTR_VALUE_TYPE); 1450 String multiple = parser.getAttributeValue(null, ATTR_MULTIPLE); 1451 if (multiple != null) { 1452 int count = Integer.parseInt(multiple); 1453 while (count > 0 && (type = parser.next()) != XmlPullParser.END_DOCUMENT) { 1454 if (type == XmlPullParser.START_TAG 1455 && parser.getName().equals(TAG_VALUE)) { 1456 values.add(parser.nextText().trim()); 1457 count--; 1458 } 1459 } 1460 String [] valueStrings = new String[values.size()]; 1461 values.toArray(valueStrings); 1462 restrictions.putStringArray(key, valueStrings); 1463 } else if (ATTR_TYPE_BOOLEAN.equals(valType)) { 1464 restrictions.putBoolean(key, Boolean.parseBoolean( 1465 parser.nextText().trim())); 1466 } else { 1467 String value = parser.nextText().trim(); 1468 restrictions.putString(key, value); 1469 } 1470 } 1471 } 1472 1473 } catch (IOException ioe) { 1474 } catch (XmlPullParserException pe) { 1475 } finally { 1476 if (fis != null) { 1477 try { 1478 fis.close(); 1479 } catch (IOException e) { 1480 } 1481 } 1482 } 1483 return restrictions; 1484 } 1485 1486 private void writeApplicationRestrictionsLocked(String packageName, 1487 Bundle restrictions, int userId) { 1488 FileOutputStream fos = null; 1489 AtomicFile restrictionsFile = new AtomicFile( 1490 new File(Environment.getUserSystemDirectory(userId), 1491 packageToRestrictionsFileName(packageName))); 1492 try { 1493 fos = restrictionsFile.startWrite(); 1494 final BufferedOutputStream bos = new BufferedOutputStream(fos); 1495 1496 // XmlSerializer serializer = XmlUtils.serializerInstance(); 1497 final XmlSerializer serializer = new FastXmlSerializer(); 1498 serializer.setOutput(bos, "utf-8"); 1499 serializer.startDocument(null, true); 1500 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 1501 1502 serializer.startTag(null, TAG_RESTRICTIONS); 1503 1504 for (String key : restrictions.keySet()) { 1505 Object value = restrictions.get(key); 1506 serializer.startTag(null, TAG_ENTRY); 1507 serializer.attribute(null, ATTR_KEY, key); 1508 1509 if (value instanceof Boolean) { 1510 serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_BOOLEAN); 1511 serializer.text(value.toString()); 1512 } else if (value == null || value instanceof String) { 1513 serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_STRING); 1514 serializer.text(value != null ? (String) value : ""); 1515 } else { 1516 serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_STRING_ARRAY); 1517 String[] values = (String[]) value; 1518 serializer.attribute(null, ATTR_MULTIPLE, Integer.toString(values.length)); 1519 for (String choice : values) { 1520 serializer.startTag(null, TAG_VALUE); 1521 serializer.text(choice != null ? choice : ""); 1522 serializer.endTag(null, TAG_VALUE); 1523 } 1524 } 1525 serializer.endTag(null, TAG_ENTRY); 1526 } 1527 1528 serializer.endTag(null, TAG_RESTRICTIONS); 1529 1530 serializer.endDocument(); 1531 restrictionsFile.finishWrite(fos); 1532 } catch (Exception e) { 1533 restrictionsFile.failWrite(fos); 1534 Slog.e(LOG_TAG, "Error writing application restrictions list"); 1535 } 1536 } 1537 1538 @Override 1539 public int getUserSerialNumber(int userHandle) { 1540 synchronized (mPackagesLock) { 1541 if (!exists(userHandle)) return -1; 1542 return getUserInfoLocked(userHandle).serialNumber; 1543 } 1544 } 1545 1546 @Override 1547 public int getUserHandle(int userSerialNumber) { 1548 synchronized (mPackagesLock) { 1549 for (int userId : mUserIds) { 1550 if (getUserInfoLocked(userId).serialNumber == userSerialNumber) return userId; 1551 } 1552 // Not found 1553 return -1; 1554 } 1555 } 1556 1557 /** 1558 * Caches the list of user ids in an array, adjusting the array size when necessary. 1559 */ 1560 private void updateUserIdsLocked() { 1561 int num = 0; 1562 for (int i = 0; i < mUsers.size(); i++) { 1563 if (!mUsers.valueAt(i).partial) { 1564 num++; 1565 } 1566 } 1567 final int[] newUsers = new int[num]; 1568 int n = 0; 1569 for (int i = 0; i < mUsers.size(); i++) { 1570 if (!mUsers.valueAt(i).partial) { 1571 newUsers[n++] = mUsers.keyAt(i); 1572 } 1573 } 1574 mUserIds = newUsers; 1575 } 1576 1577 /** 1578 * Make a note of the last started time of a user and do some cleanup. 1579 * @param userId the user that was just foregrounded 1580 */ 1581 public void userForeground(int userId) { 1582 synchronized (mPackagesLock) { 1583 UserInfo user = mUsers.get(userId); 1584 long now = System.currentTimeMillis(); 1585 if (user == null || user.partial) { 1586 Slog.w(LOG_TAG, "userForeground: unknown user #" + userId); 1587 return; 1588 } 1589 if (now > EPOCH_PLUS_30_YEARS) { 1590 user.lastLoggedInTime = now; 1591 writeUserLocked(user); 1592 } 1593 // If this is not a restricted profile and there is no restrictions pin, clean up 1594 // all restrictions files that might have been left behind, else clean up just the 1595 // ones with uninstalled packages 1596 RestrictionsPinState pinState = mRestrictionsPinStates.get(userId); 1597 final long salt = pinState == null ? 0 : pinState.salt; 1598 cleanAppRestrictions(userId, (!user.isRestricted() && salt == 0)); 1599 } 1600 } 1601 1602 /** 1603 * Returns the next available user id, filling in any holes in the ids. 1604 * TODO: May not be a good idea to recycle ids, in case it results in confusion 1605 * for data and battery stats collection, or unexpected cross-talk. 1606 * @return 1607 */ 1608 private int getNextAvailableIdLocked() { 1609 synchronized (mPackagesLock) { 1610 int i = MIN_USER_ID; 1611 while (i < Integer.MAX_VALUE) { 1612 if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.get(i)) { 1613 break; 1614 } 1615 i++; 1616 } 1617 return i; 1618 } 1619 } 1620 1621 private String packageToRestrictionsFileName(String packageName) { 1622 return RESTRICTIONS_FILE_PREFIX + packageName + XML_SUFFIX; 1623 } 1624 1625 private String restrictionsFileNameToPackage(String fileName) { 1626 return fileName.substring(RESTRICTIONS_FILE_PREFIX.length(), 1627 (int) (fileName.length() - XML_SUFFIX.length())); 1628 } 1629 1630 @Override 1631 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1632 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1633 != PackageManager.PERMISSION_GRANTED) { 1634 pw.println("Permission Denial: can't dump UserManager from from pid=" 1635 + Binder.getCallingPid() 1636 + ", uid=" + Binder.getCallingUid() 1637 + " without permission " 1638 + android.Manifest.permission.DUMP); 1639 return; 1640 } 1641 1642 long now = System.currentTimeMillis(); 1643 StringBuilder sb = new StringBuilder(); 1644 synchronized (mPackagesLock) { 1645 pw.println("Users:"); 1646 for (int i = 0; i < mUsers.size(); i++) { 1647 UserInfo user = mUsers.valueAt(i); 1648 if (user == null) continue; 1649 pw.print(" "); pw.print(user); pw.print(" serialNo="); pw.print(user.serialNumber); 1650 if (mRemovingUserIds.get(mUsers.keyAt(i))) pw.print(" <removing> "); 1651 if (user.partial) pw.print(" <partial>"); 1652 pw.println(); 1653 pw.print(" Created: "); 1654 if (user.creationTime == 0) { 1655 pw.println("<unknown>"); 1656 } else { 1657 sb.setLength(0); 1658 TimeUtils.formatDuration(now - user.creationTime, sb); 1659 sb.append(" ago"); 1660 pw.println(sb); 1661 } 1662 pw.print(" Last logged in: "); 1663 if (user.lastLoggedInTime == 0) { 1664 pw.println("<unknown>"); 1665 } else { 1666 sb.setLength(0); 1667 TimeUtils.formatDuration(now - user.lastLoggedInTime, sb); 1668 sb.append(" ago"); 1669 pw.println(sb); 1670 } 1671 } 1672 } 1673 } 1674 1675 private PackageMonitor mUserPackageMonitor = new PackageMonitor() { 1676 @Override 1677 public void onPackageRemoved(String pkg, int uid) { 1678 final int userId = this.getChangingUserId(); 1679 // Package could be disappearing because it is being blocked, so also check if 1680 // it has been uninstalled. 1681 final boolean uninstalled = isPackageDisappearing(pkg) == PACKAGE_PERMANENT_CHANGE; 1682 if (uninstalled && userId >= 0 && !isPackageInstalled(pkg, userId)) { 1683 cleanAppRestrictionsForPackage(pkg, userId); 1684 } 1685 } 1686 }; 1687} 1688