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