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