1 /* 2 * Copyright (C) 2022 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 package com.android.server.devicepolicy; 17 18 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT; 19 20 import android.annotation.Nullable; 21 import android.app.admin.SystemUpdateInfo; 22 import android.app.admin.SystemUpdatePolicy; 23 import android.content.ComponentName; 24 import android.os.UserHandle; 25 import android.util.ArrayMap; 26 import android.util.AtomicFile; 27 import android.util.IndentingPrintWriter; 28 import android.util.Log; 29 import android.util.Slog; 30 import android.util.Xml; 31 32 import com.android.internal.annotations.VisibleForTesting; 33 import com.android.modules.utils.TypedXmlPullParser; 34 import com.android.modules.utils.TypedXmlSerializer; 35 36 import libcore.io.IoUtils; 37 38 import org.xmlpull.v1.XmlPullParserException; 39 40 import java.io.File; 41 import java.io.FileOutputStream; 42 import java.io.IOException; 43 import java.io.InputStream; 44 import java.time.LocalDate; 45 import java.util.ArrayList; 46 import java.util.List; 47 import java.util.Map; 48 49 class OwnersData { 50 private static final String TAG = "DevicePolicyManagerService"; 51 52 private static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE 53 54 // XML storing device owner info, system update policy and pending OTA update information. 55 private static final String DEVICE_OWNER_XML = "device_owner_2.xml"; 56 private static final String PROFILE_OWNER_XML = "profile_owner.xml"; 57 58 private static final String TAG_ROOT = "root"; 59 private static final String TAG_DEVICE_OWNER = "device-owner"; 60 private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy"; 61 private static final String TAG_FREEZE_PERIOD_RECORD = "freeze-record"; 62 private static final String TAG_PENDING_OTA_INFO = "pending-ota-info"; 63 private static final String TAG_PROFILE_OWNER = "profile-owner"; 64 // Holds "context" for device-owner, this must not be show up before device-owner. 65 private static final String TAG_DEVICE_OWNER_CONTEXT = "device-owner-context"; 66 private static final String TAG_DEVICE_OWNER_TYPE = "device-owner-type"; 67 private static final String TAG_DEVICE_OWNER_PROTECTED_PACKAGES = 68 "device-owner-protected-packages"; 69 private static final String TAG_POLICY_ENGINE_MIGRATION = "policy-engine-migration"; 70 71 private static final String ATTR_NAME = "name"; 72 private static final String ATTR_PACKAGE = "package"; 73 private static final String ATTR_COMPONENT_NAME = "component"; 74 private static final String ATTR_SIZE = "size"; 75 private static final String ATTR_REMOTE_BUGREPORT_URI = "remoteBugreportUri"; 76 private static final String ATTR_REMOTE_BUGREPORT_HASH = "remoteBugreportHash"; 77 private static final String ATTR_USERID = "userId"; 78 private static final String ATTR_FREEZE_RECORD_START = "start"; 79 private static final String ATTR_FREEZE_RECORD_END = "end"; 80 // Legacy attribute, its presence would mean the profile owner associated with it is 81 // managing a profile on an organization-owned device. 82 private static final String ATTR_CAN_ACCESS_DEVICE_IDS = "canAccessDeviceIds"; 83 // New attribute for profile owner of organization-owned device. 84 private static final String ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE = 85 "isPoOrganizationOwnedDevice"; 86 private static final String ATTR_DEVICE_OWNER_TYPE_VALUE = "value"; 87 88 private static final String ATTR_MIGRATED_TO_POLICY_ENGINE = "migratedToPolicyEngine"; 89 90 // Internal state for the device owner package. 91 OwnerInfo mDeviceOwner; 92 int mDeviceOwnerUserId = UserHandle.USER_NULL; 93 94 // Device owner type for a managed device. 95 final ArrayMap<String, Integer> mDeviceOwnerTypes = new ArrayMap<>(); 96 97 /** @deprecated moved to {@link ActiveAdmin#protectedPackages}. */ 98 @Deprecated 99 @Nullable 100 ArrayMap<String, List<String>> mDeviceOwnerProtectedPackages; 101 102 // Internal state for the profile owner packages. 103 final ArrayMap<Integer, OwnerInfo> mProfileOwners = new ArrayMap<>(); 104 105 // Local system update policy controllable by device owner. 106 SystemUpdatePolicy mSystemUpdatePolicy; 107 LocalDate mSystemUpdateFreezeStart; 108 LocalDate mSystemUpdateFreezeEnd; 109 110 // Pending OTA info if there is one. 111 @Nullable 112 SystemUpdateInfo mSystemUpdateInfo; 113 private final PolicyPathProvider mPathProvider; 114 115 boolean mMigratedToPolicyEngine = false; 116 OwnersData(PolicyPathProvider pathProvider)117 OwnersData(PolicyPathProvider pathProvider) { 118 mPathProvider = pathProvider; 119 } 120 load(int[] allUsers)121 void load(int[] allUsers) { 122 new DeviceOwnerReadWriter().readFromFileLocked(); 123 124 for (int userId : allUsers) { 125 new ProfileOwnerReadWriter(userId).readFromFileLocked(); 126 } 127 128 OwnerInfo profileOwner = mProfileOwners.get(mDeviceOwnerUserId); 129 ComponentName admin = profileOwner != null ? profileOwner.admin : null; 130 if (mDeviceOwner != null && admin != null) { 131 Slog.w(TAG, String.format("User %d has both DO and PO, which is not supported", 132 mDeviceOwnerUserId)); 133 } 134 } 135 136 /** 137 * @return true upon success, false otherwise. 138 */ writeDeviceOwner()139 boolean writeDeviceOwner() { 140 if (DEBUG) { 141 Log.d(TAG, "Writing to device owner file"); 142 } 143 return new DeviceOwnerReadWriter().writeToFileLocked(); 144 } 145 146 /** 147 * @return true upon success, false otherwise. 148 */ writeProfileOwner(int userId)149 boolean writeProfileOwner(int userId) { 150 if (DEBUG) { 151 Log.d(TAG, "Writing to profile owner file for user " + userId); 152 } 153 return new ProfileOwnerReadWriter(userId).writeToFileLocked(); 154 } 155 dump(IndentingPrintWriter pw)156 void dump(IndentingPrintWriter pw) { 157 boolean needBlank = false; 158 if (mDeviceOwner != null) { 159 pw.println("Device Owner: "); 160 pw.increaseIndent(); 161 mDeviceOwner.dump(pw); 162 pw.println("User ID: " + mDeviceOwnerUserId); 163 pw.decreaseIndent(); 164 needBlank = true; 165 } 166 if (mSystemUpdatePolicy != null) { 167 if (needBlank) { 168 pw.println(); 169 } 170 pw.println("System Update Policy: " + mSystemUpdatePolicy); 171 needBlank = true; 172 } 173 if (mProfileOwners != null) { 174 for (Map.Entry<Integer, OwnerInfo> entry : mProfileOwners.entrySet()) { 175 if (needBlank) { 176 pw.println(); 177 } 178 pw.println("Profile Owner (User " + entry.getKey() + "): "); 179 pw.increaseIndent(); 180 entry.getValue().dump(pw); 181 pw.decreaseIndent(); 182 needBlank = true; 183 } 184 } 185 if (mSystemUpdateInfo != null) { 186 if (needBlank) { 187 pw.println(); 188 } 189 pw.println("Pending System Update: " + mSystemUpdateInfo); 190 needBlank = true; 191 } 192 if (mSystemUpdateFreezeStart != null || mSystemUpdateFreezeEnd != null) { 193 if (needBlank) { 194 pw.println(); 195 } 196 pw.println("System update freeze record: " 197 + getSystemUpdateFreezePeriodRecordAsString()); 198 needBlank = true; 199 } 200 } 201 getSystemUpdateFreezePeriodRecordAsString()202 String getSystemUpdateFreezePeriodRecordAsString() { 203 StringBuilder freezePeriodRecord = new StringBuilder(); 204 freezePeriodRecord.append("start: "); 205 if (mSystemUpdateFreezeStart != null) { 206 freezePeriodRecord.append(mSystemUpdateFreezeStart.toString()); 207 } else { 208 freezePeriodRecord.append("null"); 209 } 210 freezePeriodRecord.append("; end: "); 211 if (mSystemUpdateFreezeEnd != null) { 212 freezePeriodRecord.append(mSystemUpdateFreezeEnd.toString()); 213 } else { 214 freezePeriodRecord.append("null"); 215 } 216 return freezePeriodRecord.toString(); 217 } 218 219 @VisibleForTesting getDeviceOwnerFile()220 File getDeviceOwnerFile() { 221 return new File(mPathProvider.getDataSystemDirectory(), DEVICE_OWNER_XML); 222 } 223 224 @VisibleForTesting getProfileOwnerFile(int userId)225 File getProfileOwnerFile(int userId) { 226 return new File(mPathProvider.getUserSystemDirectory(userId), PROFILE_OWNER_XML); 227 } 228 229 private abstract static class FileReadWriter { 230 private final File mFile; 231 FileReadWriter(File file)232 protected FileReadWriter(File file) { 233 mFile = file; 234 } 235 shouldWrite()236 abstract boolean shouldWrite(); 237 writeToFileLocked()238 boolean writeToFileLocked() { 239 if (!shouldWrite()) { 240 if (DEBUG) { 241 Log.d(TAG, "No need to write to " + mFile); 242 } 243 // No contents, remove the file. 244 if (mFile.exists()) { 245 if (DEBUG) { 246 Log.d(TAG, "Deleting existing " + mFile); 247 } 248 if (!mFile.delete()) { 249 Slog.e(TAG, "Failed to remove " + mFile.getPath()); 250 } 251 } 252 return true; 253 } 254 if (DEBUG) { 255 Log.d(TAG, "Writing to " + mFile); 256 } 257 258 final AtomicFile f = new AtomicFile(mFile); 259 FileOutputStream outputStream = null; 260 try { 261 outputStream = f.startWrite(); 262 final TypedXmlSerializer out = Xml.resolveSerializer(outputStream); 263 264 // Root tag 265 out.startDocument(null, true); 266 out.startTag(null, TAG_ROOT); 267 268 // Actual content 269 writeInner(out); 270 271 // Close root 272 out.endTag(null, TAG_ROOT); 273 out.endDocument(); 274 out.flush(); 275 276 // Commit the content. 277 f.finishWrite(outputStream); 278 outputStream = null; 279 280 } catch (IOException e) { 281 Slog.e(TAG, "Exception when writing", e); 282 if (outputStream != null) { 283 f.failWrite(outputStream); 284 } 285 return false; 286 } 287 return true; 288 } 289 readFromFileLocked()290 void readFromFileLocked() { 291 if (!mFile.exists()) { 292 if (DEBUG) { 293 Log.d(TAG, "" + mFile + " doesn't exist"); 294 } 295 return; 296 } 297 if (DEBUG) { 298 Log.d(TAG, "Reading from " + mFile); 299 } 300 final AtomicFile f = new AtomicFile(mFile); 301 InputStream input = null; 302 try { 303 input = f.openRead(); 304 final TypedXmlPullParser parser = Xml.resolvePullParser(input); 305 306 int type; 307 int depth = 0; 308 while ((type = parser.next()) != TypedXmlPullParser.END_DOCUMENT) { 309 switch (type) { 310 case TypedXmlPullParser.START_TAG: 311 depth++; 312 break; 313 case TypedXmlPullParser.END_TAG: 314 depth--; 315 // fallthrough 316 default: 317 continue; 318 } 319 // Check the root tag 320 final String tag = parser.getName(); 321 if (depth == 1) { 322 if (!TAG_ROOT.equals(tag)) { 323 Slog.e(TAG, "Invalid root tag: " + tag); 324 return; 325 } 326 continue; 327 } 328 // readInner() will only see START_TAG at depth >= 2. 329 if (!readInner(parser, depth, tag)) { 330 return; // Error 331 } 332 } 333 } catch (XmlPullParserException | IOException e) { 334 Slog.e(TAG, "Error parsing owners information file", e); 335 } finally { 336 IoUtils.closeQuietly(input); 337 } 338 } 339 writeInner(TypedXmlSerializer out)340 abstract void writeInner(TypedXmlSerializer out) throws IOException; 341 readInner(TypedXmlPullParser parser, int depth, String tag)342 abstract boolean readInner(TypedXmlPullParser parser, int depth, String tag); 343 } 344 345 private class DeviceOwnerReadWriter extends FileReadWriter { 346 DeviceOwnerReadWriter()347 protected DeviceOwnerReadWriter() { 348 super(getDeviceOwnerFile()); 349 } 350 351 @Override shouldWrite()352 boolean shouldWrite() { 353 return (mDeviceOwner != null) || (mSystemUpdatePolicy != null) 354 || (mSystemUpdateInfo != null); 355 } 356 357 @Override writeInner(TypedXmlSerializer out)358 void writeInner(TypedXmlSerializer out) throws IOException { 359 if (mDeviceOwner != null) { 360 mDeviceOwner.writeToXml(out, TAG_DEVICE_OWNER); 361 out.startTag(null, TAG_DEVICE_OWNER_CONTEXT); 362 out.attributeInt(null, ATTR_USERID, mDeviceOwnerUserId); 363 out.endTag(null, TAG_DEVICE_OWNER_CONTEXT); 364 365 } 366 367 if (!mDeviceOwnerTypes.isEmpty()) { 368 for (ArrayMap.Entry<String, Integer> entry : mDeviceOwnerTypes.entrySet()) { 369 out.startTag(null, TAG_DEVICE_OWNER_TYPE); 370 out.attribute(null, ATTR_PACKAGE, entry.getKey()); 371 out.attributeInt(null, ATTR_DEVICE_OWNER_TYPE_VALUE, entry.getValue()); 372 out.endTag(null, TAG_DEVICE_OWNER_TYPE); 373 } 374 } 375 376 if (mSystemUpdatePolicy != null) { 377 out.startTag(null, TAG_SYSTEM_UPDATE_POLICY); 378 mSystemUpdatePolicy.saveToXml(out); 379 out.endTag(null, TAG_SYSTEM_UPDATE_POLICY); 380 } 381 382 if (mSystemUpdateInfo != null) { 383 mSystemUpdateInfo.writeToXml(out, TAG_PENDING_OTA_INFO); 384 } 385 386 if (mSystemUpdateFreezeStart != null || mSystemUpdateFreezeEnd != null) { 387 out.startTag(null, TAG_FREEZE_PERIOD_RECORD); 388 if (mSystemUpdateFreezeStart != null) { 389 out.attribute( 390 null, ATTR_FREEZE_RECORD_START, mSystemUpdateFreezeStart.toString()); 391 } 392 if (mSystemUpdateFreezeEnd != null) { 393 out.attribute(null, ATTR_FREEZE_RECORD_END, mSystemUpdateFreezeEnd.toString()); 394 } 395 out.endTag(null, TAG_FREEZE_PERIOD_RECORD); 396 } 397 398 out.startTag(null, TAG_POLICY_ENGINE_MIGRATION); 399 out.attributeBoolean(null, ATTR_MIGRATED_TO_POLICY_ENGINE, mMigratedToPolicyEngine); 400 out.endTag(null, TAG_POLICY_ENGINE_MIGRATION); 401 402 } 403 404 @Override readInner(TypedXmlPullParser parser, int depth, String tag)405 boolean readInner(TypedXmlPullParser parser, int depth, String tag) { 406 if (depth > 2) { 407 return true; // Ignore 408 } 409 switch (tag) { 410 case TAG_DEVICE_OWNER: 411 mDeviceOwner = OwnerInfo.readFromXml(parser); 412 mDeviceOwnerUserId = UserHandle.USER_SYSTEM; // Set default 413 break; 414 case TAG_DEVICE_OWNER_CONTEXT: { 415 mDeviceOwnerUserId = 416 parser.getAttributeInt(null, ATTR_USERID, mDeviceOwnerUserId); 417 break; 418 } 419 case TAG_SYSTEM_UPDATE_POLICY: 420 mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser); 421 break; 422 case TAG_PENDING_OTA_INFO: 423 mSystemUpdateInfo = SystemUpdateInfo.readFromXml(parser); 424 break; 425 case TAG_FREEZE_PERIOD_RECORD: 426 String startDate = parser.getAttributeValue(null, ATTR_FREEZE_RECORD_START); 427 String endDate = parser.getAttributeValue(null, ATTR_FREEZE_RECORD_END); 428 if (startDate != null && endDate != null) { 429 mSystemUpdateFreezeStart = LocalDate.parse(startDate); 430 mSystemUpdateFreezeEnd = LocalDate.parse(endDate); 431 if (mSystemUpdateFreezeStart.isAfter(mSystemUpdateFreezeEnd)) { 432 Slog.e(TAG, "Invalid system update freeze record loaded"); 433 mSystemUpdateFreezeStart = null; 434 mSystemUpdateFreezeEnd = null; 435 } 436 } 437 break; 438 case TAG_DEVICE_OWNER_TYPE: 439 String packageName = parser.getAttributeValue(null, ATTR_PACKAGE); 440 int deviceOwnerType = parser.getAttributeInt( 441 null, ATTR_DEVICE_OWNER_TYPE_VALUE, DEVICE_OWNER_TYPE_DEFAULT); 442 mDeviceOwnerTypes.put(packageName, deviceOwnerType); 443 break; 444 // Deprecated fields below. 445 case TAG_DEVICE_OWNER_PROTECTED_PACKAGES: 446 packageName = parser.getAttributeValue(null, ATTR_PACKAGE); 447 int protectedPackagesSize = parser.getAttributeInt(null, ATTR_SIZE, 0); 448 List<String> protectedPackages = new ArrayList<>(); 449 for (int i = 0; i < protectedPackagesSize; i++) { 450 protectedPackages.add(parser.getAttributeValue(null, ATTR_NAME + i)); 451 } 452 if (mDeviceOwnerProtectedPackages == null) { 453 mDeviceOwnerProtectedPackages = new ArrayMap<>(); 454 } 455 mDeviceOwnerProtectedPackages.put(packageName, protectedPackages); 456 break; 457 case TAG_POLICY_ENGINE_MIGRATION: 458 mMigratedToPolicyEngine = parser.getAttributeBoolean( 459 null, ATTR_MIGRATED_TO_POLICY_ENGINE, false); 460 break; 461 default: 462 Slog.e(TAG, "Unexpected tag: " + tag); 463 return false; 464 465 } 466 return true; 467 } 468 } 469 470 private class ProfileOwnerReadWriter extends FileReadWriter { 471 private final int mUserId; 472 ProfileOwnerReadWriter(int userId)473 ProfileOwnerReadWriter(int userId) { 474 super(getProfileOwnerFile(userId)); 475 mUserId = userId; 476 } 477 478 @Override shouldWrite()479 boolean shouldWrite() { 480 return mProfileOwners.get(mUserId) != null; 481 } 482 483 @Override writeInner(TypedXmlSerializer out)484 void writeInner(TypedXmlSerializer out) throws IOException { 485 final OwnerInfo profileOwner = mProfileOwners.get(mUserId); 486 if (profileOwner != null) { 487 profileOwner.writeToXml(out, TAG_PROFILE_OWNER); 488 } 489 } 490 491 @Override readInner(TypedXmlPullParser parser, int depth, String tag)492 boolean readInner(TypedXmlPullParser parser, int depth, String tag) { 493 if (depth > 2) { 494 return true; // Ignore 495 } 496 switch (tag) { 497 case TAG_PROFILE_OWNER: 498 mProfileOwners.put(mUserId, OwnerInfo.readFromXml(parser)); 499 break; 500 default: 501 Slog.e(TAG, "Unexpected tag: " + tag); 502 return false; 503 504 } 505 return true; 506 } 507 } 508 509 static class OwnerInfo { 510 public final String packageName; 511 public final ComponentName admin; 512 public String remoteBugreportUri; 513 public String remoteBugreportHash; 514 public boolean isOrganizationOwnedDevice; 515 OwnerInfo(ComponentName admin, String remoteBugreportUri, String remoteBugreportHash, boolean isOrganizationOwnedDevice)516 OwnerInfo(ComponentName admin, String remoteBugreportUri, 517 String remoteBugreportHash, boolean isOrganizationOwnedDevice) { 518 this.admin = admin; 519 this.packageName = admin.getPackageName(); 520 this.remoteBugreportUri = remoteBugreportUri; 521 this.remoteBugreportHash = remoteBugreportHash; 522 this.isOrganizationOwnedDevice = isOrganizationOwnedDevice; 523 } 524 writeToXml(TypedXmlSerializer out, String tag)525 public void writeToXml(TypedXmlSerializer out, String tag) throws IOException { 526 out.startTag(null, tag); 527 if (admin != null) { 528 out.attribute(null, ATTR_COMPONENT_NAME, admin.flattenToString()); 529 } 530 if (remoteBugreportUri != null) { 531 out.attribute(null, ATTR_REMOTE_BUGREPORT_URI, remoteBugreportUri); 532 } 533 if (remoteBugreportHash != null) { 534 out.attribute(null, ATTR_REMOTE_BUGREPORT_HASH, remoteBugreportHash); 535 } 536 if (isOrganizationOwnedDevice) { 537 out.attributeBoolean( 538 null, ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE, isOrganizationOwnedDevice); 539 } 540 out.endTag(null, tag); 541 } 542 readFromXml(TypedXmlPullParser parser)543 public static OwnerInfo readFromXml(TypedXmlPullParser parser) { 544 final String componentName = parser.getAttributeValue(null, ATTR_COMPONENT_NAME); 545 final String remoteBugreportUri = 546 parser.getAttributeValue(null, ATTR_REMOTE_BUGREPORT_URI); 547 final String remoteBugreportHash = 548 parser.getAttributeValue(null, ATTR_REMOTE_BUGREPORT_HASH); 549 final String canAccessDeviceIdsStr = 550 parser.getAttributeValue(null, ATTR_CAN_ACCESS_DEVICE_IDS); 551 final boolean canAccessDeviceIds = "true".equals(canAccessDeviceIdsStr); 552 final String isOrgOwnedDeviceStr = 553 parser.getAttributeValue(null, ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE); 554 final boolean isOrgOwnedDevice = 555 "true".equals(isOrgOwnedDeviceStr) | canAccessDeviceIds; 556 557 if (componentName == null) { 558 Slog.e(TAG, "Owner component not found"); 559 return null; 560 } 561 final ComponentName admin = ComponentName.unflattenFromString(componentName); 562 if (admin == null) { 563 Slog.e(TAG, "Owner component not parsable: " + componentName); 564 return null; 565 } 566 567 return new OwnerInfo(admin, remoteBugreportUri, remoteBugreportHash, isOrgOwnedDevice); 568 } 569 dump(IndentingPrintWriter pw)570 public void dump(IndentingPrintWriter pw) { 571 pw.println("admin=" + admin); 572 pw.println("package=" + packageName); 573 pw.println("isOrganizationOwnedDevice=" + isOrganizationOwnedDevice); 574 } 575 } 576 } 577