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