1 /* 2 * Copyright (C) 2014 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 17 package com.android.server.devicepolicy; 18 19 import android.annotation.Nullable; 20 import android.app.admin.SystemUpdateInfo; 21 import android.app.admin.SystemUpdatePolicy; 22 import android.content.ComponentName; 23 import android.content.pm.PackageManagerInternal; 24 import android.content.pm.UserInfo; 25 import android.os.Environment; 26 import android.os.UserHandle; 27 import android.os.UserManager; 28 import android.os.UserManagerInternal; 29 import android.util.ArrayMap; 30 import android.util.AtomicFile; 31 import android.util.Log; 32 import android.util.Pair; 33 import android.util.Slog; 34 import android.util.SparseArray; 35 import android.util.Xml; 36 37 import com.android.internal.util.FastXmlSerializer; 38 39 import org.xmlpull.v1.XmlPullParser; 40 import org.xmlpull.v1.XmlPullParserException; 41 import org.xmlpull.v1.XmlSerializer; 42 43 import java.io.File; 44 import java.io.FileOutputStream; 45 import java.io.IOException; 46 import java.io.InputStream; 47 import java.io.PrintWriter; 48 import java.nio.charset.StandardCharsets; 49 import java.util.List; 50 import java.util.Map; 51 import java.util.Objects; 52 import java.util.Set; 53 54 import libcore.io.IoUtils; 55 56 /** 57 * Stores and restores state for the Device and Profile owners and related device-wide information. 58 * By definition there can be only one device owner, but there may be a profile owner for each user. 59 * 60 * <p>This class is thread safe, so individual methods can safely be called without locking. 61 * However, caller must still synchronize on their side to ensure integrity between multiple calls. 62 */ 63 class Owners { 64 private static final String TAG = "DevicePolicyManagerService"; 65 66 private static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE 67 68 private static final String DEVICE_OWNER_XML_LEGACY = "device_owner.xml"; 69 70 // XML storing device owner info, system update policy and pending OTA update information. 71 private static final String DEVICE_OWNER_XML = "device_owner_2.xml"; 72 73 private static final String PROFILE_OWNER_XML = "profile_owner.xml"; 74 75 private static final String TAG_ROOT = "root"; 76 77 private static final String TAG_DEVICE_OWNER = "device-owner"; 78 private static final String TAG_DEVICE_INITIALIZER = "device-initializer"; 79 private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy"; 80 private static final String TAG_PENDING_OTA_INFO = "pending-ota-info"; 81 private static final String TAG_PROFILE_OWNER = "profile-owner"; 82 // Holds "context" for device-owner, this must not be show up before device-owner. 83 private static final String TAG_DEVICE_OWNER_CONTEXT = "device-owner-context"; 84 85 private static final String ATTR_NAME = "name"; 86 private static final String ATTR_PACKAGE = "package"; 87 private static final String ATTR_COMPONENT_NAME = "component"; 88 private static final String ATTR_REMOTE_BUGREPORT_URI = "remoteBugreportUri"; 89 private static final String ATTR_REMOTE_BUGREPORT_HASH = "remoteBugreportHash"; 90 private static final String ATTR_USERID = "userId"; 91 private static final String ATTR_USER_RESTRICTIONS_MIGRATED = "userRestrictionsMigrated"; 92 93 private final UserManager mUserManager; 94 private final UserManagerInternal mUserManagerInternal; 95 private final PackageManagerInternal mPackageManagerInternal; 96 97 // Internal state for the device owner package. 98 private OwnerInfo mDeviceOwner; 99 100 private int mDeviceOwnerUserId = UserHandle.USER_NULL; 101 102 // Internal state for the profile owner packages. 103 private final ArrayMap<Integer, OwnerInfo> mProfileOwners = new ArrayMap<>(); 104 105 // Local system update policy controllable by device owner. 106 private SystemUpdatePolicy mSystemUpdatePolicy; 107 108 // Pending OTA info if there is one. 109 @Nullable 110 private SystemUpdateInfo mSystemUpdateInfo; 111 112 private final Object mLock = new Object(); 113 114 public Owners(UserManager userManager, 115 UserManagerInternal userManagerInternal, 116 PackageManagerInternal packageManagerInternal) { 117 mUserManager = userManager; 118 mUserManagerInternal = userManagerInternal; 119 mPackageManagerInternal = packageManagerInternal; 120 } 121 122 /** 123 * Load configuration from the disk. 124 */ 125 void load() { 126 synchronized (mLock) { 127 // First, try to read from the legacy file. 128 final File legacy = getLegacyConfigFileWithTestOverride(); 129 130 final List<UserInfo> users = mUserManager.getUsers(true); 131 132 if (readLegacyOwnerFileLocked(legacy)) { 133 if (DEBUG) { 134 Log.d(TAG, "Legacy config file found."); 135 } 136 137 // Legacy file exists, write to new files and remove the legacy one. 138 writeDeviceOwner(); 139 for (int userId : getProfileOwnerKeys()) { 140 writeProfileOwner(userId); 141 } 142 if (DEBUG) { 143 Log.d(TAG, "Deleting legacy config file"); 144 } 145 if (!legacy.delete()) { 146 Slog.e(TAG, "Failed to remove the legacy setting file"); 147 } 148 } else { 149 // No legacy file, read from the new format files. 150 new DeviceOwnerReadWriter().readFromFileLocked(); 151 152 for (UserInfo ui : users) { 153 new ProfileOwnerReadWriter(ui.id).readFromFileLocked(); 154 } 155 } 156 mUserManagerInternal.setDeviceManaged(hasDeviceOwner()); 157 for (UserInfo ui : users) { 158 mUserManagerInternal.setUserManaged(ui.id, hasProfileOwner(ui.id)); 159 } 160 if (hasDeviceOwner() && hasProfileOwner(getDeviceOwnerUserId())) { 161 Slog.w(TAG, String.format("User %d has both DO and PO, which is not supported", 162 getDeviceOwnerUserId())); 163 } 164 pushToPackageManagerLocked(); 165 } 166 } 167 168 private void pushToPackageManagerLocked() { 169 final SparseArray<String> po = new SparseArray<>(); 170 for (int i = mProfileOwners.size() - 1; i >= 0; i--) { 171 po.put(mProfileOwners.keyAt(i), mProfileOwners.valueAt(i).packageName); 172 } 173 mPackageManagerInternal.setDeviceAndProfileOwnerPackages( 174 mDeviceOwnerUserId, (mDeviceOwner != null ? mDeviceOwner.packageName : null), 175 po); 176 } 177 178 String getDeviceOwnerPackageName() { 179 synchronized (mLock) { 180 return mDeviceOwner != null ? mDeviceOwner.packageName : null; 181 } 182 } 183 184 int getDeviceOwnerUserId() { 185 synchronized (mLock) { 186 return mDeviceOwnerUserId; 187 } 188 } 189 190 @Nullable 191 Pair<Integer, ComponentName> getDeviceOwnerUserIdAndComponent() { 192 synchronized (mLock) { 193 if (mDeviceOwner == null) { 194 return null; 195 } else { 196 return Pair.create(mDeviceOwnerUserId, mDeviceOwner.admin); 197 } 198 } 199 } 200 201 String getDeviceOwnerName() { 202 synchronized (mLock) { 203 return mDeviceOwner != null ? mDeviceOwner.name : null; 204 } 205 } 206 207 ComponentName getDeviceOwnerComponent() { 208 synchronized (mLock) { 209 return mDeviceOwner != null ? mDeviceOwner.admin : null; 210 } 211 } 212 213 String getDeviceOwnerRemoteBugreportUri() { 214 synchronized (mLock) { 215 return mDeviceOwner != null ? mDeviceOwner.remoteBugreportUri : null; 216 } 217 } 218 219 String getDeviceOwnerRemoteBugreportHash() { 220 synchronized (mLock) { 221 return mDeviceOwner != null ? mDeviceOwner.remoteBugreportHash : null; 222 } 223 } 224 225 void setDeviceOwner(ComponentName admin, String ownerName, int userId) { 226 if (userId < 0) { 227 Slog.e(TAG, "Invalid user id for device owner user: " + userId); 228 return; 229 } 230 synchronized (mLock) { 231 // For a newly set DO, there's no need for migration. 232 setDeviceOwnerWithRestrictionsMigrated(admin, ownerName, userId, 233 /* userRestrictionsMigrated =*/ true); 234 } 235 } 236 237 // Note this should be only called during migration. Normally when DO is set, 238 // userRestrictionsMigrated should always be true. 239 void setDeviceOwnerWithRestrictionsMigrated(ComponentName admin, String ownerName, int userId, 240 boolean userRestrictionsMigrated) { 241 synchronized (mLock) { 242 mDeviceOwner = new OwnerInfo(ownerName, admin, userRestrictionsMigrated, 243 /* remoteBugreportUri =*/ null, /* remoteBugreportHash =*/ null); 244 mDeviceOwnerUserId = userId; 245 246 mUserManagerInternal.setDeviceManaged(true); 247 pushToPackageManagerLocked(); 248 } 249 } 250 251 void clearDeviceOwner() { 252 synchronized (mLock) { 253 mDeviceOwner = null; 254 mDeviceOwnerUserId = UserHandle.USER_NULL; 255 256 mUserManagerInternal.setDeviceManaged(false); 257 pushToPackageManagerLocked(); 258 } 259 } 260 261 void setProfileOwner(ComponentName admin, String ownerName, int userId) { 262 synchronized (mLock) { 263 // For a newly set PO, there's no need for migration. 264 mProfileOwners.put(userId, new OwnerInfo(ownerName, admin, 265 /* userRestrictionsMigrated =*/ true, /* remoteBugreportUri =*/ null, 266 /* remoteBugreportHash =*/ null)); 267 mUserManagerInternal.setUserManaged(userId, true); 268 pushToPackageManagerLocked(); 269 } 270 } 271 272 void removeProfileOwner(int userId) { 273 synchronized (mLock) { 274 mProfileOwners.remove(userId); 275 mUserManagerInternal.setUserManaged(userId, false); 276 pushToPackageManagerLocked(); 277 } 278 } 279 280 ComponentName getProfileOwnerComponent(int userId) { 281 synchronized (mLock) { 282 OwnerInfo profileOwner = mProfileOwners.get(userId); 283 return profileOwner != null ? profileOwner.admin : null; 284 } 285 } 286 287 String getProfileOwnerName(int userId) { 288 synchronized (mLock) { 289 OwnerInfo profileOwner = mProfileOwners.get(userId); 290 return profileOwner != null ? profileOwner.name : null; 291 } 292 } 293 294 String getProfileOwnerPackage(int userId) { 295 synchronized (mLock) { 296 OwnerInfo profileOwner = mProfileOwners.get(userId); 297 return profileOwner != null ? profileOwner.packageName : null; 298 } 299 } 300 301 Set<Integer> getProfileOwnerKeys() { 302 synchronized (mLock) { 303 return mProfileOwners.keySet(); 304 } 305 } 306 307 SystemUpdatePolicy getSystemUpdatePolicy() { 308 synchronized (mLock) { 309 return mSystemUpdatePolicy; 310 } 311 } 312 313 void setSystemUpdatePolicy(SystemUpdatePolicy systemUpdatePolicy) { 314 synchronized (mLock) { 315 mSystemUpdatePolicy = systemUpdatePolicy; 316 } 317 } 318 319 void clearSystemUpdatePolicy() { 320 synchronized (mLock) { 321 mSystemUpdatePolicy = null; 322 } 323 } 324 325 boolean hasDeviceOwner() { 326 synchronized (mLock) { 327 return mDeviceOwner != null; 328 } 329 } 330 331 boolean isDeviceOwnerUserId(int userId) { 332 synchronized (mLock) { 333 return mDeviceOwner != null && mDeviceOwnerUserId == userId; 334 } 335 } 336 337 boolean hasProfileOwner(int userId) { 338 synchronized (mLock) { 339 return getProfileOwnerComponent(userId) != null; 340 } 341 } 342 343 /** 344 * @return true if user restrictions need to be migrated for DO. 345 */ 346 boolean getDeviceOwnerUserRestrictionsNeedsMigration() { 347 synchronized (mLock) { 348 return mDeviceOwner != null && !mDeviceOwner.userRestrictionsMigrated; 349 } 350 } 351 352 /** 353 * @return true if user restrictions need to be migrated for PO. 354 */ 355 boolean getProfileOwnerUserRestrictionsNeedsMigration(int userId) { 356 synchronized (mLock) { 357 OwnerInfo profileOwner = mProfileOwners.get(userId); 358 return profileOwner != null && !profileOwner.userRestrictionsMigrated; 359 } 360 } 361 362 /** Sets the user restrictions migrated flag, and also writes to the file. */ 363 void setDeviceOwnerUserRestrictionsMigrated() { 364 synchronized (mLock) { 365 if (mDeviceOwner != null) { 366 mDeviceOwner.userRestrictionsMigrated = true; 367 } 368 writeDeviceOwner(); 369 } 370 } 371 372 /** Sets the remote bugreport uri and hash, and also writes to the file. */ 373 void setDeviceOwnerRemoteBugreportUriAndHash(String remoteBugreportUri, 374 String remoteBugreportHash) { 375 synchronized (mLock) { 376 if (mDeviceOwner != null) { 377 mDeviceOwner.remoteBugreportUri = remoteBugreportUri; 378 mDeviceOwner.remoteBugreportHash = remoteBugreportHash; 379 } 380 writeDeviceOwner(); 381 } 382 } 383 384 /** Sets the user restrictions migrated flag, and also writes to the file. */ 385 void setProfileOwnerUserRestrictionsMigrated(int userId) { 386 synchronized (mLock) { 387 OwnerInfo profileOwner = mProfileOwners.get(userId); 388 if (profileOwner != null) { 389 profileOwner.userRestrictionsMigrated = true; 390 } 391 writeProfileOwner(userId); 392 } 393 } 394 395 private boolean readLegacyOwnerFileLocked(File file) { 396 if (!file.exists()) { 397 // Already migrated or the device has no owners. 398 return false; 399 } 400 try { 401 InputStream input = new AtomicFile(file).openRead(); 402 XmlPullParser parser = Xml.newPullParser(); 403 parser.setInput(input, StandardCharsets.UTF_8.name()); 404 int type; 405 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT) { 406 if (type!=XmlPullParser.START_TAG) { 407 continue; 408 } 409 410 String tag = parser.getName(); 411 if (tag.equals(TAG_DEVICE_OWNER)) { 412 String name = parser.getAttributeValue(null, ATTR_NAME); 413 String packageName = parser.getAttributeValue(null, ATTR_PACKAGE); 414 mDeviceOwner = new OwnerInfo(name, packageName, 415 /* userRestrictionsMigrated =*/ false, /* remoteBugreportUri =*/ null, 416 /* remoteBugreportHash =*/ null); 417 mDeviceOwnerUserId = UserHandle.USER_SYSTEM; 418 } else if (tag.equals(TAG_DEVICE_INITIALIZER)) { 419 // Deprecated tag 420 } else if (tag.equals(TAG_PROFILE_OWNER)) { 421 String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE); 422 String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME); 423 String profileOwnerComponentStr = 424 parser.getAttributeValue(null, ATTR_COMPONENT_NAME); 425 int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID)); 426 OwnerInfo profileOwnerInfo = null; 427 if (profileOwnerComponentStr != null) { 428 ComponentName admin = ComponentName.unflattenFromString( 429 profileOwnerComponentStr); 430 if (admin != null) { 431 profileOwnerInfo = new OwnerInfo(profileOwnerName, admin, 432 /* userRestrictionsMigrated =*/ false, null, null); 433 } else { 434 // This shouldn't happen but switch from package name -> component name 435 // might have written bad device owner files. b/17652534 436 Slog.e(TAG, "Error parsing device-owner file. Bad component name " + 437 profileOwnerComponentStr); 438 } 439 } 440 if (profileOwnerInfo == null) { 441 profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName, 442 /* userRestrictionsMigrated =*/ false, 443 /* remoteBugreportUri =*/ null, /* remoteBugreportHash =*/ null); 444 } 445 mProfileOwners.put(userId, profileOwnerInfo); 446 } else if (TAG_SYSTEM_UPDATE_POLICY.equals(tag)) { 447 mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser); 448 } else { 449 throw new XmlPullParserException( 450 "Unexpected tag in device owner file: " + tag); 451 } 452 } 453 input.close(); 454 } catch (XmlPullParserException|IOException e) { 455 Slog.e(TAG, "Error parsing device-owner file", e); 456 } 457 return true; 458 } 459 460 void writeDeviceOwner() { 461 synchronized (mLock) { 462 if (DEBUG) { 463 Log.d(TAG, "Writing to device owner file"); 464 } 465 new DeviceOwnerReadWriter().writeToFileLocked(); 466 } 467 } 468 469 void writeProfileOwner(int userId) { 470 synchronized (mLock) { 471 if (DEBUG) { 472 Log.d(TAG, "Writing to profile owner file for user " + userId); 473 } 474 new ProfileOwnerReadWriter(userId).writeToFileLocked(); 475 } 476 } 477 478 /** 479 * Saves the given {@link SystemUpdateInfo} if it is different from the existing one, or if 480 * none exists. 481 * 482 * @return Whether the saved system update information has changed. 483 */ 484 boolean saveSystemUpdateInfo(@Nullable SystemUpdateInfo newInfo) { 485 synchronized (mLock) { 486 // Check if we already have the same update information. 487 if (Objects.equals(newInfo, mSystemUpdateInfo)) { 488 return false; 489 } 490 491 mSystemUpdateInfo = newInfo; 492 new DeviceOwnerReadWriter().writeToFileLocked(); 493 return true; 494 } 495 } 496 497 @Nullable 498 public SystemUpdateInfo getSystemUpdateInfo() { 499 synchronized (mLock) { 500 return mSystemUpdateInfo; 501 } 502 } 503 504 private abstract static class FileReadWriter { 505 private final File mFile; 506 507 protected FileReadWriter(File file) { 508 mFile = file; 509 } 510 511 abstract boolean shouldWrite(); 512 513 void writeToFileLocked() { 514 if (!shouldWrite()) { 515 if (DEBUG) { 516 Log.d(TAG, "No need to write to " + mFile); 517 } 518 // No contents, remove the file. 519 if (mFile.exists()) { 520 if (DEBUG) { 521 Log.d(TAG, "Deleting existing " + mFile); 522 } 523 if (!mFile.delete()) { 524 Slog.e(TAG, "Failed to remove " + mFile.getPath()); 525 } 526 } 527 return; 528 } 529 if (DEBUG) { 530 Log.d(TAG, "Writing to " + mFile); 531 } 532 533 final AtomicFile f = new AtomicFile(mFile); 534 FileOutputStream outputStream = null; 535 try { 536 outputStream = f.startWrite(); 537 final XmlSerializer out = new FastXmlSerializer(); 538 out.setOutput(outputStream, StandardCharsets.UTF_8.name()); 539 540 // Root tag 541 out.startDocument(null, true); 542 out.startTag(null, TAG_ROOT); 543 544 // Actual content 545 writeInner(out); 546 547 // Close root 548 out.endTag(null, TAG_ROOT); 549 out.endDocument(); 550 out.flush(); 551 552 // Commit the content. 553 f.finishWrite(outputStream); 554 outputStream = null; 555 556 } catch (IOException e) { 557 Slog.e(TAG, "Exception when writing", e); 558 if (outputStream != null) { 559 f.failWrite(outputStream); 560 } 561 } 562 } 563 564 void readFromFileLocked() { 565 if (!mFile.exists()) { 566 if (DEBUG) { 567 Log.d(TAG, "" + mFile + " doesn't exist"); 568 } 569 return; 570 } 571 if (DEBUG) { 572 Log.d(TAG, "Reading from " + mFile); 573 } 574 final AtomicFile f = new AtomicFile(mFile); 575 InputStream input = null; 576 try { 577 input = f.openRead(); 578 final XmlPullParser parser = Xml.newPullParser(); 579 parser.setInput(input, StandardCharsets.UTF_8.name()); 580 581 int type; 582 int depth = 0; 583 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { 584 switch (type) { 585 case XmlPullParser.START_TAG: 586 depth++; 587 break; 588 case XmlPullParser.END_TAG: 589 depth--; 590 // fallthrough 591 default: 592 continue; 593 } 594 // Check the root tag 595 final String tag = parser.getName(); 596 if (depth == 1) { 597 if (!TAG_ROOT.equals(tag)) { 598 Slog.e(TAG, "Invalid root tag: " + tag); 599 return; 600 } 601 continue; 602 } 603 // readInner() will only see START_TAG at depth >= 2. 604 if (!readInner(parser, depth, tag)) { 605 return; // Error 606 } 607 } 608 } catch (XmlPullParserException | IOException e) { 609 Slog.e(TAG, "Error parsing owners information file", e); 610 } finally { 611 IoUtils.closeQuietly(input); 612 } 613 } 614 615 abstract void writeInner(XmlSerializer out) throws IOException; 616 617 abstract boolean readInner(XmlPullParser parser, int depth, String tag); 618 } 619 620 private class DeviceOwnerReadWriter extends FileReadWriter { 621 622 protected DeviceOwnerReadWriter() { 623 super(getDeviceOwnerFileWithTestOverride()); 624 } 625 626 @Override 627 boolean shouldWrite() { 628 return (mDeviceOwner != null) || (mSystemUpdatePolicy != null) 629 || (mSystemUpdateInfo != null); 630 } 631 632 @Override 633 void writeInner(XmlSerializer out) throws IOException { 634 if (mDeviceOwner != null) { 635 mDeviceOwner.writeToXml(out, TAG_DEVICE_OWNER); 636 out.startTag(null, TAG_DEVICE_OWNER_CONTEXT); 637 out.attribute(null, ATTR_USERID, String.valueOf(mDeviceOwnerUserId)); 638 out.endTag(null, TAG_DEVICE_OWNER_CONTEXT); 639 } 640 641 if (mSystemUpdatePolicy != null) { 642 out.startTag(null, TAG_SYSTEM_UPDATE_POLICY); 643 mSystemUpdatePolicy.saveToXml(out); 644 out.endTag(null, TAG_SYSTEM_UPDATE_POLICY); 645 } 646 647 if (mSystemUpdateInfo != null) { 648 mSystemUpdateInfo.writeToXml(out, TAG_PENDING_OTA_INFO); 649 } 650 } 651 652 @Override 653 boolean readInner(XmlPullParser parser, int depth, String tag) { 654 if (depth > 2) { 655 return true; // Ignore 656 } 657 switch (tag) { 658 case TAG_DEVICE_OWNER: 659 mDeviceOwner = OwnerInfo.readFromXml(parser); 660 mDeviceOwnerUserId = UserHandle.USER_SYSTEM; // Set default 661 break; 662 case TAG_DEVICE_OWNER_CONTEXT: { 663 final String userIdString = 664 parser.getAttributeValue(null, ATTR_USERID); 665 try { 666 mDeviceOwnerUserId = Integer.parseInt(userIdString); 667 } catch (NumberFormatException e) { 668 Slog.e(TAG, "Error parsing user-id " + userIdString); 669 } 670 break; 671 } 672 case TAG_DEVICE_INITIALIZER: 673 // Deprecated tag 674 break; 675 case TAG_SYSTEM_UPDATE_POLICY: 676 mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser); 677 break; 678 case TAG_PENDING_OTA_INFO: 679 mSystemUpdateInfo = SystemUpdateInfo.readFromXml(parser); 680 break; 681 default: 682 Slog.e(TAG, "Unexpected tag: " + tag); 683 return false; 684 685 } 686 return true; 687 } 688 } 689 690 private class ProfileOwnerReadWriter extends FileReadWriter { 691 private final int mUserId; 692 693 ProfileOwnerReadWriter(int userId) { 694 super(getProfileOwnerFileWithTestOverride(userId)); 695 mUserId = userId; 696 } 697 698 @Override 699 boolean shouldWrite() { 700 return mProfileOwners.get(mUserId) != null; 701 } 702 703 @Override 704 void writeInner(XmlSerializer out) throws IOException { 705 final OwnerInfo profileOwner = mProfileOwners.get(mUserId); 706 if (profileOwner != null) { 707 profileOwner.writeToXml(out, TAG_PROFILE_OWNER); 708 } 709 } 710 711 @Override 712 boolean readInner(XmlPullParser parser, int depth, String tag) { 713 if (depth > 2) { 714 return true; // Ignore 715 } 716 switch (tag) { 717 case TAG_PROFILE_OWNER: 718 mProfileOwners.put(mUserId, OwnerInfo.readFromXml(parser)); 719 break; 720 default: 721 Slog.e(TAG, "Unexpected tag: " + tag); 722 return false; 723 724 } 725 return true; 726 } 727 } 728 729 static class OwnerInfo { 730 public final String name; 731 public final String packageName; 732 public final ComponentName admin; 733 public boolean userRestrictionsMigrated; 734 public String remoteBugreportUri; 735 public String remoteBugreportHash; 736 737 public OwnerInfo(String name, String packageName, boolean userRestrictionsMigrated, 738 String remoteBugreportUri, String remoteBugreportHash) { 739 this.name = name; 740 this.packageName = packageName; 741 this.admin = new ComponentName(packageName, ""); 742 this.userRestrictionsMigrated = userRestrictionsMigrated; 743 this.remoteBugreportUri = remoteBugreportUri; 744 this.remoteBugreportHash = remoteBugreportHash; 745 } 746 747 public OwnerInfo(String name, ComponentName admin, boolean userRestrictionsMigrated, 748 String remoteBugreportUri, String remoteBugreportHash) { 749 this.name = name; 750 this.admin = admin; 751 this.packageName = admin.getPackageName(); 752 this.userRestrictionsMigrated = userRestrictionsMigrated; 753 this.remoteBugreportUri = remoteBugreportUri; 754 this.remoteBugreportHash = remoteBugreportHash; 755 } 756 757 public void writeToXml(XmlSerializer out, String tag) throws IOException { 758 out.startTag(null, tag); 759 out.attribute(null, ATTR_PACKAGE, packageName); 760 if (name != null) { 761 out.attribute(null, ATTR_NAME, name); 762 } 763 if (admin != null) { 764 out.attribute(null, ATTR_COMPONENT_NAME, admin.flattenToString()); 765 } 766 out.attribute(null, ATTR_USER_RESTRICTIONS_MIGRATED, 767 String.valueOf(userRestrictionsMigrated)); 768 if (remoteBugreportUri != null) { 769 out.attribute(null, ATTR_REMOTE_BUGREPORT_URI, remoteBugreportUri); 770 } 771 if (remoteBugreportHash != null) { 772 out.attribute(null, ATTR_REMOTE_BUGREPORT_HASH, remoteBugreportHash); 773 } 774 out.endTag(null, tag); 775 } 776 777 public static OwnerInfo readFromXml(XmlPullParser parser) { 778 final String packageName = parser.getAttributeValue(null, ATTR_PACKAGE); 779 final String name = parser.getAttributeValue(null, ATTR_NAME); 780 final String componentName = 781 parser.getAttributeValue(null, ATTR_COMPONENT_NAME); 782 final String userRestrictionsMigratedStr = 783 parser.getAttributeValue(null, ATTR_USER_RESTRICTIONS_MIGRATED); 784 final boolean userRestrictionsMigrated = 785 ("true".equals(userRestrictionsMigratedStr)); 786 final String remoteBugreportUri = parser.getAttributeValue(null, 787 ATTR_REMOTE_BUGREPORT_URI); 788 final String remoteBugreportHash = parser.getAttributeValue(null, 789 ATTR_REMOTE_BUGREPORT_HASH); 790 791 // Has component name? If so, return [name, component] 792 if (componentName != null) { 793 final ComponentName admin = ComponentName.unflattenFromString(componentName); 794 if (admin != null) { 795 return new OwnerInfo(name, admin, userRestrictionsMigrated, 796 remoteBugreportUri, remoteBugreportHash); 797 } else { 798 // This shouldn't happen but switch from package name -> component name 799 // might have written bad device owner files. b/17652534 800 Slog.e(TAG, "Error parsing owner file. Bad component name " + 801 componentName); 802 } 803 } 804 805 // Else, build with [name, package] 806 return new OwnerInfo(name, packageName, userRestrictionsMigrated, remoteBugreportUri, 807 remoteBugreportHash); 808 } 809 810 public void dump(String prefix, PrintWriter pw) { 811 pw.println(prefix + "admin=" + admin); 812 pw.println(prefix + "name=" + name); 813 pw.println(prefix + "package=" + packageName); 814 } 815 } 816 817 public void dump(String prefix, PrintWriter pw) { 818 boolean needBlank = false; 819 if (mDeviceOwner != null) { 820 pw.println(prefix + "Device Owner: "); 821 mDeviceOwner.dump(prefix + " ", pw); 822 pw.println(prefix + " User ID: " + mDeviceOwnerUserId); 823 needBlank = true; 824 } 825 if (mSystemUpdatePolicy != null) { 826 if (needBlank) { 827 pw.println(); 828 } 829 pw.println(prefix + "System Update Policy: " + mSystemUpdatePolicy); 830 needBlank = true; 831 } 832 if (mProfileOwners != null) { 833 for (Map.Entry<Integer, OwnerInfo> entry : mProfileOwners.entrySet()) { 834 if (needBlank) { 835 pw.println(); 836 } 837 pw.println(prefix + "Profile Owner (User " + entry.getKey() + "): "); 838 entry.getValue().dump(prefix + " ", pw); 839 needBlank = true; 840 } 841 } 842 if (mSystemUpdateInfo != null) { 843 if (needBlank) { 844 pw.println(); 845 } 846 pw.println(prefix + "Pending System Update: " + mSystemUpdateInfo); 847 needBlank = true; 848 } 849 } 850 851 File getLegacyConfigFileWithTestOverride() { 852 return new File(Environment.getDataSystemDirectory(), DEVICE_OWNER_XML_LEGACY); 853 } 854 855 File getDeviceOwnerFileWithTestOverride() { 856 return new File(Environment.getDataSystemDirectory(), DEVICE_OWNER_XML); 857 } 858 859 File getProfileOwnerFileWithTestOverride(int userId) { 860 return new File(Environment.getUserSystemDirectory(userId), PROFILE_OWNER_XML); 861 } 862 } 863