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